-
Notifications
You must be signed in to change notification settings - Fork 13
Constraints and exceptions
Constraints are restricting rules for regulating log levels. If no constraints are specified, then all log levels are allowed.
-
Min/max constraints allow levels between min and max values inclusive (for example, info thru error). Both min and max don't have to be present. So, you can allow all log levels above min level OR below max one. Use keywords 'minlevel' and 'maxlevel' to set these constraints.
-
List of constraints allows levels only specified in a list. For example, you can feed the string "debug, info, critical" to say logger you want these three levels. Use keyword 'levels' to set this kind of constraints.
There are two types of constraints: global constraints and exception constraints
Global constraints are meant to be used all over the application, they are 'regularly applied' rules (as opposed to 'exceptions'). These constraints are set in the seelog root element attributes.
To allow only log levels 'info' and above, start your config with:
<seelog minlevel="info">
To allow levels from info to error (i.e. info, warn, error), use:
<seelog minlevel="info" maxlevel="error">
To allow only a specific set of levels (say, trace, info, and critical), start your config with:
<seelog levels="trace,info,critical">
Exceptions, as opposed to general rules, are thought as special cases which break (loosen or strengthen) the regular rules (general constraints). For example, you may want to restrict logging for a specific file or group of files. Vice versa: you have really restricting global constraints and you want to allow specific files or funcs to log at a deeper level.
An exception consists of 'filepattern', 'funcpattern' and constraint ('minlevel'/'maxlevel' or 'levels). So, if you want to override general rules for functions or files (or both of them) with a specific name pattern, you specify the pattern in the 'filepattern'/'funcpattern' fields and use the overriding constraint.
When you perform logging for each log the runtime.Caller function is called under the hood to get the current context. Then we find the first exception which pattern the file/func names meet. If such an exception is found, its constraints override the general constraints.
According to the things said above, there are some simple recommendations:
- Be moderate with exceptions. As we run through exception list each time something is logged, it's a bad idea to cram it with rules, just a few should be okay. There was a reason we called them exceptions!
- Avoid constraints which allow 'trace' or 'debug' levels in production configs. If you do that, you will tell the Analyzer that 'traces/debugs are allowed somewhere', and all Trace/Debug calls won't just return instantly, but instead will force the constraint checker to run every time runtime.Caller, then fall through exception list, etc. However, such constraints are okay for development or production systems where performance is not crucial. (See the examples below)
- Use more specific rules first. This is just because we use exactly the first exception which pattern the file/func names meet. So, if your file name meets the 'filepattern' of an exception - the exception subsystem will immediately use this one's constraints and won't look at exceptions that go after. More specific rules - first, less specific rules - last. (See the examples below)
Let's create more restricting rules for all files, beginning with "test".
<seelog minlevel="info">
<exceptions>
<exception filepattern="test*" minlevel="error"/>
</exceptions>
This way you will get 'info', 'warn', 'error', 'critical' messages for all files, but the ones starting with "test". For files starting with "test" you will only get "error" and "critical" messages.
One more example. Now let's create a reverse situation: let's allow only 'critical' messages as a general rule, but allow "warn, error, critical" levels for a function "main.testFunc" (package 'main', func 'testFunc'):
<seelog levels="critical">
<exceptions>
<exception funcpattern="main.testFunc" minlevel="warn"/>
</exceptions>
Let's create a production-ready config:
<seelog minlevel="info">
<exceptions>
<exception funcpattern="main.testFunc" minlevel="warn"/>
<exception funcpattern="main.testFunc2" minlevel="error"/>
<exception funcpattern="*test*" filepattern="tests.go" levels="off"/>
<exception funcpattern="*perfCritical" minlevel="critical"/>
</exceptions>
...
This config is totally okay for production, because it doesn't have any exceptions which allow levels 'trace' or 'debug'
Let's test the 'more common exceptions first' rule:
<seelog minlevel="info">
<exceptions>
<exception funcpattern="main.testFunc" levels="critical"/>
<exception funcpattern="main.test*" minlevel="error"/>
<exception funcpattern="main.*" minlevel="warn"/>
</exceptions>
...
This config would work exactly as it seems to. But if you wrote these exceptions in other order - it won't be the same. For example, if you put the exception with "main.*" pattern first then the two other exceptions would be just ignored.
'Off' is a special log level that means that logging is disabled. It can be used both in minlevel and levels constraints, so you could both write a 'minlevel="off"' and 'levels="off"' in global or exception constraints to disable log.
A working example of different configurations exceptions/constraints can be found here: examples/exceptions