Log events are written to the receiver via methods on the Log static class or the ILogger interface. The following examples will use Log for syntactic simplicity, but the methods shown below can be used with the interface as well.
("Disk quota {Quota} MB exceeded by {User}", quota, user);
The warning event created by this logging method will have two associated attributes, Quota and User. assuming quota is an integer and user is a string, the message rendered might look like the following.
Disk quota 1024 MB exceeded by "nblumhardt"
(Serilog renders string values using double quotes to more clearly indicate their underlying data type and to make property values stand out from the surrounding message text.)
01. Message template syntax
The above string "Disk quota {Quota} exceeded by {User}" is a Serilog message template. Message templates are a superset of standard .NET format strings, so any format string that applies to () will also be handled correctly by Serilog.
- Attribute names are written enclosed in { and }.
- The property name must be a valid C# identifier, such as FooBar, but not or Foo-Bar.
- Parentheses can be escaped by repeated writing, e.g. {{ will be rendered as {.
- Using a format of numeric attribute names, such as {0} and {1}, will match the arguments to the log method by treating the attribute name as an index; this is the same behavior as ().
- If any attribute name is non-numeric, all attribute names will be matched from left to right against the parameters of the log method.
- Attribute names can have the optional operator prefix @ or $ to control how the attribute is serialized.
- Attribute names may be accompanied by optional formatting suffixes, such as :000, to control how the attribute is rendered; these formatting strings behave in exactly the same way as their counterparts in the () syntax.
02、Message template recommendation
Fluency style guide: good Serilog events use property names as message contents, as in the user example above. This improves readability and makes the event more concise.
Sentences vs. fragments: log event messages are fragments, not sentences; for consistency with other libraries that use Serilog, try to avoid periods at the end of sentences.
Templates vs. messages: Serilog events are associated with message templates, not messages. Internally, Serilog parses and caches each template (up to a fixed size limit). Treating string arguments to log methods as messages, as shown in the following example, degrades performance and consumes cache memory.
// Not recommended
("The time is " + );
Instead, always use the template attribute to include variables in the message
// Recommended
("The time is {Now}", );
Property naming: Property names should use PascalCase to maintain consistency with other code and libraries in the Serilog ecosystem.
03. Log event level
Serilog uses levels as the primary means of assigning importance to log events. The levels are in increasing order of importance:
- Details (Verbose) - Trace information and debugging details; usually turned on only in special cases.
- Debug - Internal control flow and diagnostic status dumps to facilitate localization of known problems.
- Information - Events that are meaningful or relevant to an external observer; the lowest logging level enabled by default.
- Warning - An indication of a possible problem or service/function degradation.
- Error - Indicates a failure in the application or connection system.
- Fatal - A serious error that causes the application to fail completely.
1. The role of information levels
The information level is different from the other specified levels-it has no specific semantics and in many ways expresses what is missing from the other levels.
Since Serilog allows the event stream of an application to be processed or analyzed, the information level can be considered synonymous with events. That is, most interesting application event data should be recorded at this level.
2. Level detection
In most cases, applications should log events without checking the current logging level. The overhead of level checking is very low, as is the overhead of calling disabled logging methods.
In a few performance-sensitive cases, the recommended pattern for level detection is to store the results of the level detection in a field, for example:
readonly bool _isDebug = ();
The _isDebug field can be efficiently checked before writing log events:
if (_isDebug) ("Someone is stuck debugging...");
3. Dynamic levels
Many large or distributed applications need to run at relatively restricted logging levels, such as informational (which I prefer) or warning, and it makes sense to increase the logging level to debug or detail only when a problem is detected so that the overhead of collecting more data is justified.
If the application needs to dynamically switch logging levels, the first step is to create an instance of LoggingLevelSwitch when configuring the logger:
var levelSwitch = new LoggingLevelSwitch();
This object sets the current lowest level to informational by default, so to make logging more rigorous, you can set its lowest level in advance:
= ;
Use () to provide this switch when configuring the logger:
var log = new LoggerConfiguration()
.(levelSwitch)
.()
.CreateLogger();
Events written to the logger are now filtered based on the MinimumLevel property of the switch.
To adjust the logging level at runtime, for example in response to commands sent over the network, you can change this property:
= ;
("This will now be logged");
04. Source context
Serilog, like most .NET logging frameworks, allows events to take their source tag with them, usually the name of the class that wrote them:
var myLog = <MyClass>();
("Hello!");
Events written will contain a property SourceContext with a value of "" that can be used to filter noise events or selectively write them to specific receivers.
Not all properties attached to an event need to be represented in a message template or output format; all properties are stored in the dictionary of the underlying LogEvent object.
For more information on filters and logging topologies, see the Serilog Documentation Translation Series (III) - Basic Configuration knowledge.
05. Associations
Just as the ForContext
var job = GetNextJob();
var jobLog = ("JobId", );
("Running a new job");
();
("Finished");
Here, both log events will carry the JobId property, which contains the job identifier.
Tip: When logging to a receiver that uses text formatting, e.g. , you can include {Properties} in the output template to print out all contextual properties that are not included.
Note: All relevant source code has been uploaded to the code base for those interested./hugogoos/Planner