Bad NLog callsite for a WCF logging behavior -


i writing logging behavior in this blog pieter de rycke, nlog. came code:

public class nloglogger : iparameterinspector {     private void log(type instancetype, string operationname, string msg)     {         nlog.logger logger = logmanager.getlogger(             instancetype.fullname, instancetype);         logger.info(msg, instancetype);     }      public object beforecall(string operationname, object[] inputs)     {         // retrieve service instance type logger log call.         operationcontext operationcontext = operationcontext.current;         type instancetype = operationcontext.instancecontext             .getserviceinstance().gettype();         log(instancetype, operationname, "beforecall");          return instancetype;     }      public void aftercall(         string operationname, object[] outputs,         object returnvalue, object correlationstate     )     {         if (correlationstate type)             log(correlationstate type, operationname, "aftercall");     } } 

the logging behavior works fine. injected service example.myservice using attribute described pieter. have layout in nlog target:

${longdate} ${callsite} ${level:uppercase=true} ${message} 

however callsite operation getcontacts wrong:

2013-07-11 13:32:53.1379 common.nloglogger.log info beforecall 2013-07-11 13:32:53.7121 common.nloglogger.log info aftercall 

correct this:

2013-07-11 13:32:53.1379 example.myservice.getcontacts info beforecall 2013-07-11 13:32:53.7121 example.myservice.getcontacts info aftercall 

what have tried?

nlog offers special handling of callsite logging wrappers or facades, described in stackoverflow answer: pass class of callsite logging methods.

in fact did logger.info(msg, instancetype) above in log() method. not work because callsite not yet in stack trace when behavior's beforecall() method running. wcf has not yet started run operation. nlog not find callsite in stack trace , not capable unwrap stack trace.

how can fake callsite? or how can display "right" callsite logging behavior?

update:

thanks clarification, better understand trying do. messages logged iparameterinspector implementation reflect call site of "example.myservice.getcontacts" example.myservice service (as indicated instancetype parameter) , "getcontacts" operation. synthesize call site information manually. still use nlog's logger.log method , still create logeventinfo object. additionally, can store "class" , "method" in logeventinfo.properties object. rather retrieving logger (from logmanager) based on instancetype (i.e. service), retrieve logger based on type of parameter inspector (nloglogger in case). finally, can add additional rule nlog.config (and apply nloglogger type) rule has different logging format. manually add field logging format contains call site information (that stored in logeventinfo.properties collection) in same position "real" callsite layoutrenderer in other logging rule configurations.

next post new version of nloglogger implementation described above.

public class nloglogger : iparameterinspector {     private static readonly nlog.logger logger = logmanager.getcurrentclasslogger();      private void log(type instancetype, string operationname, string msg)     {         nlog.logger servicelogger = logmanager.getlogger(             instancetype.fullname, instancetype);          //create logeventinfo logger.name logger associated service         logeventinfo le = new logeventinfo(loglevel.info, servicelogger.name, msg);         le.properties.add("fakecallsite", string.format("{0}.{1}",instancetype.tostring(),operationname);          //log message using parameter inspector's logger.         logger.log(typeof(nloglogger), le);     }      public object beforecall(string operationname, object[] inputs)     {         // retrieve service instance type logger log call.         operationcontext operationcontext = operationcontext.current;         type instancetype = operationcontext.instancecontext             .getserviceinstance().gettype();         log(instancetype, operationname, "beforecall");          return instancetype;     }      public void aftercall(         string operationname, object[] outputs,         object returnvalue, object correlationstate     )     {         if (correlationstate type)             log(correlationstate, operationname, "aftercall");     } } 

your nlog.config have rules this. 1 rule nloglogger parameter inspector. logs "f1" , "final" rule, meaning logging messages parameter inspector won't logged other rules. other rule other loggers. each logs different file target, both file targets write same file (which works, think). key each file has own layout.

<logger name="your.full.namespace.nloglogger" minlevel="*" writeto="f1" final="true" />  <logger name="*" minlevel="*" writeto="f2" />  

your targets , layouts this. defining variable value value of eventpropertieslayoutrenderer, fake call site stored in logeventinfo.properties["fakecallsite"].

  <variable name="fakecallsite" value="${event-properties:fakecallsite}"/>   <variable name="f1layout" value="${longdate} | ${level} | ${logger} | ${fakecallsite} | ${message}"/>   <variable name="f2layout" value="${longdate} | ${level} | ${logger} | ${callsite} | ${message}"/>   <targets>     <target name="f1" xsi:type="file" layout="${f1layout}" filename="${basedir}/${shortdate}.log" />     <target name="f2" xsi:type="file" layout="${f2layout}" filename="${basedir}/${shortdate}.log"        />   </targets> 

note have not tried this, think should work (or should close enough can working). 1 limitation that, since calculating fake call site, cannot use real callsite layoutrenderer manipulate contents of fakecallsite field in output. if important, can simulated storing class , method separately (in logeventinfo.properties) , setting "fakecallsite" variable in nlog.config contain class, method, or both.

end update

your wrapper should use log method. also, type pass nlog logger.log method should type of nlog logger wrapper, not type of type of service instance. can still use type of service instance retrieve right logger instance. should this:

public class nloglogger : iparameterinspector {     private void log(type instancetype, string operationname, string msg)     {         nlog.logger logger = logmanager.getlogger(             instancetype.fullname, instancetype);          //this key preserving call site in wrapper.  create logeventinfo         //then use nlog's logger.log method log message, passing type of          //wrapper first argument.          logeventinfo le = new logeventinfo(loglevel.info, logger.name, msg);         logger.log(typeof(nloglogger), le);     }      public object beforecall(string operationname, object[] inputs)     {         // retrieve service instance type logger log call.         operationcontext operationcontext = operationcontext.current;         type instancetype = operationcontext.instancecontext             .getserviceinstance().gettype();         log(instancetype, operationname, "beforecall");          return instancetype;     }      public void aftercall(         string operationname, object[] outputs,         object returnvalue, object correlationstate     )     {         if (correlationstate type)             log(correlationstate, operationname, "aftercall");     } } 

Comments