Hello logrus folks!
It was mentioned in issue #121 that being able to make your own custom log levels would be a feature by 1.0, wanted to make a place to track the feature's progress.
Thanks for the great work!
@yoiang Do you have a proposal for how this would work?
hey @stevvooe! Do you mean what would the API look like or how would it actually be implemented in logrus' guts technically? I am not expert with either but can take some time and figure it out depending on what you're asking!
@yoiang So, the issue is that we already have values that have an ordering. Allowing users to define these may have an impact on how that ordering interacts. Without going into details, bolting this on is likely pretty complex.
@sirupsen may have a more detailed plan for how this might work.
I suggest simply exposing logrus.Entry.Log(Level, string) (and logrus.Entry.Logf(Level, string, ...interface{})) and adding a logrus.SetCustomLevelName(Level, string) and logrus.GetCustomLevelName(Level) string, bool which are simply backed by a thread-safe map. Then logrus.Level.String() can use the latter before defaulting to "unknown".
Then we can all simply create levels via:
const TraceLevel = logrus.DebugLevel + 1
func init() {
logrus.SetCustomLevelName(TraceLevel, "trace")
}
This of course does not solve issues where people may want their level in between other levels. The way to solve that with a backwards compatible impl is to keep the Level type and make a new interface and what not:
type Leveler interface {
Cmp(other Leveler) int
LevelString() string
}
func (level Level) Cmp(other Leveler) int {
switch other := other.(type) {
case Level:
if level > other {
return 1
} else if level < other {
return -1
}
return 0
default:
return -other.Cmp(level)
}
}
func (level Level) LevelString() string { return level.String() }
Then of course have logrus.Entry.Log(Leveler, string) and logrus.Entry.Logf(Leveler, string, ...interface{}). Granted it may have a bit of performance overhead introducing a type switch in every log statement, but it's a thought. I think the first proposal is good enough to solve people's notice/trace wants (or just go ahead and acknowledge there's a level below debug for many common use cases).
@cretz Would it be sufficient just to add a Trace level to logrus? I'm really not sure about the effect bolting something on like this.
@stevvooe See you here! :D
@cretz I agree with you. In Kubernetes, we usually have:
info)debug)trace is useful.)In cri-containerd, we were using glog previously, and I'm trying to move to logrus to make the log output consistent with containerd. However, this become a issue blocking us.
+1 for custom log levels
+1
Just like glog.V(x), we could filter out most of spammy log.
+1 for user implemented log levels. A use case that we use a lot that might not have been considered is Cloudwatch Log filtering into Cloudwatch Metrics. In most languages we create a log level called Metric that is generally very high, somewhere above Warn or Error depending on the language. This way our logs that contain metrics that need to be processed are always logged in all environments without extremely verbose logs. Currently with logrus I would have to log these at Info or patch them into Warn which would be weird.
FWIW @defendertx's comment is exactly the reason I found this issue by searching "logrus custom level" in Google
+1 for custom log levels
Logrus now (and for a while) has had a Trace level and corresponding methods. That seems to address all the use cases I read through in this issue.
Additionally there are Log, Logf, & Logln methods which take arbitrary levels.
I think the only thing missing is the way that existing levels are somewhat hard coded, making extension / customization of them a bit hard. Related to that: https://github.com/sirupsen/logrus/pull/1009#issuecomment-545218036
Suddenly I think Trace level fits most of needs but not all.
For example custom log levels could be useful also for audit logging, suddenly with current log levels it's very complex to find place for them, and creating custom log level for them could be a good option
Closing per the project being put into maintenance mode
Most helpful comment
@stevvooe - Yes, but it has been explicitly rejected multiple times.
FWIW, I disagree w/ the rejections. In my lib I have
Tracefthat I just check my own level state on before just sending it off toDebugfwhich is good enough for me.