In log4net, I want to append a request id to every log statement for a particular http request. Request id's are distinct across multiple requests. In my global.asax.cs I assign a requestId.
protected void Application_BeginRequest(object sender, EventArgs e)
{
log4net.GlobalContext.Properties["requestId"] =
System.Guid.NewGuid().ToString();
log.Info("Starting request.");
}
In my Log4Net.config I added the requestId to my pattern layout:
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%property{requestId} %d [%t] %-5p %c %m%n"/>
</layout>
Is the approach of using GlobalContext to set a variable threadsafe? Am I at risk of a concurrent http request unsafely changing the requestId for the logging of another request?
If this is unsafe, what is a safe way to implement?
No it is not correct; the global context is shared across all threads and domains. Two threads setting the same property on the GlobalContext
would overwrite one another's property. log4net.GlobalContext.Properties["requestId"]
will always contain the request id of the latest request started.
Being threadsafe doesn't mean thread independent: it means that the object can be manipulated by multiple threads at the same time.
Use the ThreadContext
which lives per thread and will let you have a property per thread (hence per request, assuming your thread doesn't delegate work to another thread at some point):
log4net.ThreadContext.Properties["requestId"]
It works for me. I have exactly this scenario, a multi-threading application that must send different information to the log depends on the thread context.
Using ThreadContext instead of GlobalContext works like a charm.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With