You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4net-dev@logging.apache.org by josh robb <jo...@fastmail.fm> on 2006/02/15 14:46:07 UTC

log4net Contexts and ASP.NET

I've seen an email from Piers Williams in december asking about this.

Basically - in an ASP.NET application - none of the existing contexts
are "safe" to use.

I'd like to remedy this. There are two ways forward that I can see.

1. Add a new WebContext class.
2. Change the ThreadLogicalContext class to use the HttpContext if
required. The safest way to do this would be to add a configuration
option to <log4net isWeb="true"> and test for this in
ThreadLogicalContext.

I (probably) prefer 2 because it means your Business layer does not
need to be aware of whether or not it is running in a web context.

Has anyone got any thoughts on this or done any work here already?

j.

Re: log4net Contexts and ASP.NET

Posted by josh robb <jo...@fastmail.fm>.
On 2/16/06, Aaron Morton <lo...@the-mortons.org> wrote:
> Perhaps you could create something similar (add objects to the
> GlobalContext) to read values from the HTTPContext  as a work around.

Nice - Ok - for the two things I've mentioned so far (User Identity
and Requested Url) this would be a fine solution. This allows us to
safely capture state about a request.

However for business layer logging - where the context is dependant on
the actual action performed this does not sound like it would work
well. (i.e. the contextual information is dependant on the actual
sequence of actions performed with a single request).

Thanks for the useful ideas! (They solve my immediate problems).
However I still have several problems:

1. ThreadLogicalContext  is demonstrably not safe for use in a ASP.NET
environment. (Not just in pages but in any components used by those
pages).
2. This is not documented or mentioned anywhere.
3. There is no log4net support/recommended alternative (or
pattern/best practice).

j.

Re: log4net Contexts and ASP.NET

Posted by Aaron Morton <lo...@the-mortons.org>.
Josh,
    I've been doing something similar with remoting Contexts. I'm 
putting some objects into a new Context, and using ContextProperties to 
inject message sinks which intercept some calls and add information to 
the Context Property. In this case i'm not using the 
ThreadLogicalContext as i want these properties to be present at all 
times in the object on all threads, and dont want to have to add them 
for each call (as is my understanding with the CallContext used by 
ThreadLogicalContext)

To get the property values into log messages I've created a type that in 
its ToString() gets a specified ContextProperty and returns it's 
ToString(). Then  I add as many of these to the GlobalContext as i need, 
following the "Active Property Values" pattern here 
http://logging.apache.org/log4net/release/manual/contexts.html

Perhaps you could create something similar (add objects to the 
GlobalContext) to read values from the HTTPContext  as a work around.

aaron

josh robb wrote:

>I've seen an email from Piers Williams in december asking about this.
>
>Basically - in an ASP.NET application - none of the existing contexts
>are "safe" to use.
>
>I'd like to remedy this. There are two ways forward that I can see.
>
>1. Add a new WebContext class.
>2. Change the ThreadLogicalContext class to use the HttpContext if
>required. The safest way to do this would be to add a configuration
>option to <log4net isWeb="true"> and test for this in
>ThreadLogicalContext.
>
>I (probably) prefer 2 because it means your Business layer does not
>need to be aware of whether or not it is running in a web context.
>
>Has anyone got any thoughts on this or done any work here already?
>
>j.
>
>  
>


Re: log4net Contexts and ASP.NET

Posted by Chad Humphries <ch...@gmail.com>.
Sorry, I blanked and completely glazed over the first line of your email. :)

-Chad

On 2/15/06, josh robb <jo...@fastmail.fm> wrote:
> Yep - Thats the email I was talking about.
>
> Thanks for the reply.
>
> j.
>

Re: log4net Contexts and ASP.NET

Posted by josh robb <jo...@fastmail.fm>.
Yep - Thats the email I was talking about.

Thanks for the reply.

j.

Re: log4net Contexts and ASP.NET

Posted by Chad Humphries <ch...@gmail.com>.
Josh,

I remember seeing some chatter about this (I think adaptive context)
here (http://mail-archives.apache.org/mod_mbox/logging-log4net-user/200512.mbox/%3Cce0154420512081629j138e20f8h@mail.gmail.com%3E)
and here (http://www.mail-archive.com/log4net-user@logging.apache.org/msg02670.html).

I'm not sure if any movement has been made yet, although I'm sure
someone will chime in if there was a decision/movement made.

-Chad

On 2/15/06, josh robb <jo...@fastmail.fm> wrote:
> I've seen an email from Piers Williams in december asking about this.
>
> Basically - in an ASP.NET application - none of the existing contexts
> are "safe" to use.
>
> I'd like to remedy this. There are two ways forward that I can see.
>
> 1. Add a new WebContext class.
> 2. Change the ThreadLogicalContext class to use the HttpContext if
> required. The safest way to do this would be to add a configuration
> option to <log4net isWeb="true"> and test for this in
> ThreadLogicalContext.
>
> I (probably) prefer 2 because it means your Business layer does not
> need to be aware of whether or not it is running in a web context.
>
> Has anyone got any thoughts on this or done any work here already?
>
> j.
>

Re: log4net Contexts and ASP.NET

Posted by Ron Grabowski <ro...@yahoo.com>.
If there's a global "isWeb" setting, you wouldn't be able to easily
tell certain loggers (i.e. a certain namespaces) to use CallContext.
What about setting the LogicalThreadContext's storage at the logger
level? 

 <root>
  <level value="ALL" />
  <appender-ref ref="FileAppender" />
  <logicalThreadContextProperties 
    type="log4net.Util.LogicalThreadContextProperties" />
 </root>		
 <logger name="Company.Website">
  <level value="ALL" />
  <logicalThreadContextProperties 
    type="log4net.Util.HttpContextLogicalThreadContextProperties" />
  <appender-ref ref="WebsiteFileAppender" />
 </logger>
 <logger name="Company.Website.BackgroundThreads">
  <level value="ALL" />
  <logicalThreadContextProperties 
    type="log4net.Util.LogicalThreadContextProperties" />
  <appender-ref ref="BackgroundThreadsFileAppender" />
 </logger>

In the example above, the Company.Website.BackgroundThreads namespace
contains loggers who don't have access to HttpContext.

Appenders already do something similiar with their SecurityContext
property. Its possible for every appender to have a unique
SecurityContext implementation. We could make a
LogicalThreadContextPropertiesProvider class that mimics
SecurityContextProvider in that the DefaultProvider property returns
either a normal CallContext storage provider or a HttpContext storage
provider. Would there also need to be specialized property patterns
that know where to look? My idea sounds overly complex :-/

--- josh robb <jo...@fastmail.fm> wrote:

> On 2/16/06, GlennDoten <gd...@gmail.com> wrote:
> >  Josh, why bother with a flag called isWeb? If HttpContext.Current
> is not
> > null then you know you are in the context of a web app; otherwise
> you
> > aren't. It works great just checking the HTTP context because then
> the same
> > code can execute in a web app or a non-web app.
> 
> Thanks for the feedback - I initially thought of this - but I thought
> it made sense to keep the new behaviour optional. (It's possible to
> imagine circumstances where you'd rather use the CallContext even if
> you're in the middle of a web request).
> 
> Are we getting close to agreement about what the patch should look
> like? If so I can knock something together - to hopefully generate
> some more discussion.
> 
> j.
> 


Re: log4net Contexts and ASP.NET

Posted by josh robb <jo...@fastmail.fm>.
On 2/16/06, GlennDoten <gd...@gmail.com> wrote:
>  Josh, why bother with a flag called isWeb? If HttpContext.Current is not
> null then you know you are in the context of a web app; otherwise you
> aren't. It works great just checking the HTTP context because then the same
> code can execute in a web app or a non-web app.

Thanks for the feedback - I initially thought of this - but I thought
it made sense to keep the new behaviour optional. (It's possible to
imagine circumstances where you'd rather use the CallContext even if
you're in the middle of a web request).

Are we getting close to agreement about what the patch should look
like? If so I can knock something together - to hopefully generate
some more discussion.

j.

Re: log4net Contexts and ASP.NET

Posted by GlennDoten <gd...@gmail.com>.
On 2/16/06, josh robb <jo...@fastmail.fm> wrote:
>
> Conceptually - this is what I'm proposing:
>
> if(isWeb and HttpContent.Current != null)  {
>    // store context in HttpContext.Current.Items
> } else {
>    // sore it in CallContext.
> }
>

Josh, why bother with a flag called isWeb? If HttpContext.Current is not
null then you know you are in the context of a web app; otherwise you
aren't. It works great just checking the HTTP context because then the same
code can execute in a web app or a non-web app.

I too don't see any issues with log4net referencing System.Web either, or
System.Remoting for that matter if it has anything needed in it for this
functionality.

--
-glenn-

Re: log4net Contexts and ASP.NET

Posted by josh robb <jo...@fastmail.fm>.
Ron Grabowski <ro...@yahoo.com> wrote:
> I don't think HttpContext is always available...especially inside the
> Global.asax.cs methods and/or inside CacheItemRemovedCallback methods.

HttpContext is available during the life cycle of a Http request. This
includes any event handler in Global.asax which is associated with
Request handling. (The only one off the top of my head where this is
not the case would be Session_End - which has it's own problems).

> HttpContext is just a wrapper around
> System.Runtime.Remoting.Messaging.CallContext. Log4Net doesn't have a
> reference any of the Remoting libraries.

HttpContext uses CallContext but it is not _just_ a wrapper. Peirs
outlines this very clearly in an execlent post:
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html

"Under load ASP.Net can migrate inbound requests from its IO thread
pool to a queue taken up by it's worker process thread pool"

Under asp.net 2 - this appears to happen as a matter of course (due to
the async processing support?). This means that Context info will be
leaked between requests. (Which shouldn't happen).

I don't understand the relevance of your comment about references to
Remoting. (log4net already references System.Web).

> If you know that HttpContext is a better place to store thread specific
> information, you could do this:

HttpContext is the _only_ safe place to store information related to
one HttpRequest. (e.g. currently authenticated user, Requested Url
etc....) This is because ASP.NET can (and does) migrate HttpRequests
between threads during the processing of a single request.

> Making your business layer call through to your own static methods for
> storing items in the MDC would put you in a good position if anything
> changes later on:
>
>  Company.Logging.ThreadContext.Properties["NAME"] = getUserName();

I'm happy to write whatever is required (a custom MDC or formatter or
whatever) but there should be 1 documented and supported solution for
log4net which supports logging contexts running under ASP.NET.

In my opinion - this should involve changing the ThreadLogicalContext
so that it can be used in the business layer. I mentioned adding a
configuration option to enable using HttpContent. I should have added
that even if that option is enabled then HttpContext would need to be
checked and if it is unavailable then CallContext should be used as it
is currently. (If HttpContext.Current is null - then CallContext is
the right place for context info as it's the HtppRequest processing
infrastructure that does the thread migration anyway).

Conceptually - this is what I'm proposing:

if(isWeb and HttpContent.Current != null)  {
   // store context in HttpContext.Current.Items
} else {
   // sore it in CallContext.
}

j.

(Peirs - are you on this list?)

Re: log4net Contexts and ASP.NET

Posted by Ron Grabowski <ro...@yahoo.com>.
I don't think HttpContext is always available...especially inside the
Global.asax.cs methods and/or inside CacheItemRemovedCallback methods.

According to this article:

 http://www.odetocode.com/Articles/112.aspx

HttpContext is just a wrapper around
System.Runtime.Remoting.Messaging.CallContext. Log4Net doesn't have a
reference any of the Remoting libraries.

If you know that HttpContext is a better place to store thread specific
information, you could do this:

 <layout type="log4net.Layout.PatternLayout">
  <converter>
   <name value="httpContextMdc" />
   <type value="Company.Logging.HttpContextMdc" />
  </converter>
  <conversionPattern value="%message %httpContextMdc{NAME}%newline" />
 </layout>

Or maybe even override the %X, %MDC, etc. to look in HttpContext by
writing your own PatternLayout:

 <layout type="Company.Logging.HttpContextMdcPatternLayout">
  <conversionPattern value="%message %X{NAME}%newline" />
 </layout>

Making your business layer call through to your own static methods for
storing items in the MDC would put you in a good position if anything
changes later on:

 Company.Logging.ThreadContext.Properties["NAME"] = getUserName();

--- josh robb <jo...@fastmail.fm> wrote:

> I've seen an email from Piers Williams in december asking about this.
> 
> Basically - in an ASP.NET application - none of the existing contexts
> are "safe" to use.
> 
> I'd like to remedy this. There are two ways forward that I can see.
> 
> 1. Add a new WebContext class.
> 2. Change the ThreadLogicalContext class to use the HttpContext if
> required. The safest way to do this would be to add a configuration
> option to <log4net isWeb="true"> and test for this in
> ThreadLogicalContext.
> 
> I (probably) prefer 2 because it means your Business layer does not
> need to be aware of whether or not it is running in a web context.
> 
> Has anyone got any thoughts on this or done any work here already?
> 
> j.
>