serilog-expressions
serilog-expressions copied to clipboard
Clarify documentation around @x
The README states:
@x - the exception associated with the event, if any, as an Exception
which implies to me that you are able to access the properties of that exception.
In reality however, @x
is simply a ToString()
'd version of the exception, and to get hold of its properties you need to write a custom ILogEventEnricher
. It would be extremely helpful to update the README with this information.
Hi! Thanks for raising this @IanKemp 👍
It's actually a bit of a corner case right now; the documentation is correct - the value of @x
is an actual Exception
object:
https://github.com/serilog/serilog-expressions/blob/dev/src/Serilog.Expressions/Expressions/Compilation/Linq/LinqExpressionCompiler.cs#L208
And if you use SerilogExpression.TryCompile("@x", ...)
and invoke the resulting delegate with a LogEvent
, you'll get a ScalarValue { Value = <some exception> }
back.
But, there aren't yet any functions for manipulating exceptions in the rest of the language/library, so there's no way to e.g. retrieve the message, stack trace, or other properties individually, and thus the only way to format it out as text right now is to let it be ToString()
ed.
The plan is to add some support functions to the RuntimeOperators
that make it possible to turn the opaque Exception
object into a data structure and traverse it, along the lines of:
CaptureException(@x).Message
where CaptureException
would, stepping only one layer deep through inner exceptions etc., provide a StructureValue
with message, stack trace, data, inner exception and innerexceptions (if an AggregateException
).
The case of the exception type is already handled by TypeOf(@x)
.
What does your use case look like, when implemented with CaptureException()
?
Our use case is emitting logs in a format that Datadog can ingress and use in its metrics, specifically the error.*
properties as documented here. It sounds like CaptureException
would do exactly what we need, but I do think it is important to update the README to clarify that this feature isn't yet available and until then, it's necessary to use ILogEventEnricher
.
I have an implementation of the "capture" function on the way, just a few small details left to figure out, so I'll include that in the README update. Should be done in a day or two.
Ah yea I found this confusing as well. As initially I tried to access fields of @x
. i.e. @x.StackTrace
After a bit of trial and fail I realised it wasn't possible, although wasn't sure entirely why. So moved to using Properties (@p
) and adding what I needed via Log.Context()
specifically.
I then noticed that the documentation never actually says that you can get fields from @x
and I had just assumed it was the real exception object. So clarifying exactly what @x
is, in the documentation would be beneficial to new users.
#109 includes some README updates as well as the new function, it'd be great to have some more eyes on it :)
#109 includes some README updates as well as the new function, it'd be great to have some more eyes on it :)
Personally, I find the extra details on the variable @x
being after the list of variables a bit odd and allows it to be missed when doing searches for @x
. Is it there as you wanted to keep the main variable list entries concise or for another reason?
The content of the extra details about @x
looks clear to me.
- All first-class properties of the event - no special syntax:
SourceContext
andCart
are used in the formatting examples above@t
- the event's timestamp, as aDateTimeOffset
@m
- the rendered message@mt
- the raw message template@l
- the event's level, as aLogEventLevel
@x
- the exception associated with the event, if any, as anException
@p
- a dictionary containing all first-class properties; this supports properties with non-identifier names, for example@p['snake-case-name']
@i
- event id; a 32-bit numeric hash of the event's message template@r
- renderings; if any tokens in the message template include .NET-specific formatting, an array of rendered values for each such tokenThe built-in properties mirror those available in the CLEF format.
The exception property
@x
is treated as a scalar and will appear as a string when formatted into text. The properties of the underlyingException
object can be accessed usingInspect()
, for exampleInspect(@x).Message
, and the type of the exception retrieved usingTypeOf(@x)
.
The description of the Inspect()
function looks a little light to me.
- The textual description doesn't lead me to think that it returns the object for accessing the properties of. Also, when would that be required given
@p
can just have the.
or[]
notations used. - An example of its usage would seem beneficial there, like
@x
has. - Also, what does the [Deep] argument do for the function.