[ 
https://issues.apache.org/jira/browse/LOG4NET-615?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Daniel Lidström updated LOG4NET-615:
------------------------------------
    Description: 
Hello

 

I'm trying to create a structured logging format and have a conversion pattern 
with a custom converter like this:

 

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%date [%2thread] %-5level [%property\\{NDC}] 
%username - type=%message_checksum %message%newline" />

        <converter>

          <name value="message_checksum" />

          <type value="TestBed.MessageChecksumConverter" />

        </converter>

      </layout>

 

The interesting part of course is the message_checksum. For example, I am 
logging like this:

 

                Log.Debug("some debugging message");

                Log.Info(new \{ Id = 1, Name = "the name" });

                Log.InfoFormat("Logging msg \{0}", 1);

                Log.InfoFormat("Logging msg \{0}", 2);

                Log.InfoFormat("Logging msg \{0}", 3);

 

I would like the output to be something like this

 

2018-10-26 11:06:44,564 [ 1] DEBUG [(null)] XXX - type=f6d5 some debugging 
message

2018-10-26 11:06:44,638 [ 1] INFO  [(null)] XXX - type=e0e3 \{ Id = 1, Name = 
the name }

2018-10-26 11:06:44,648 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 1

2018-10-26 11:06:44,656 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 2

2018-10-26 11:06:44,663 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 3

 

As you can see, I am getting the type=32a6 for the last 3 logging messages. 
This allows me to search for all of those, regardless of the parameters given.

For example, I can now search and group the number of errors by their unique 
type and know which error is most common in our system.

 

To implement this, I did the following:

public class MessageChecksumConverter : PatternLayoutConverter
 {
 private static readonly TraceSource Source = new 
TraceSource(nameof(MessageChecksumConverter));
 private static readonly MD5 ChecksumGenerator = MD5.Create();

protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
 {
 var output = TryGetHash(loggingEvent);
 writer.Write(output);
 }

private string TryGetHash(LoggingEvent loggingEvent)
 {
 string output = string.Empty;
 try
 {
 byte[] hash;
 var fmt = loggingEvent.MessageObject as SystemStringFormat;
 if (fmt != null)
 {
 // read fmt.m_format and use that as input for hash
 var systemStringFormatType = typeof(SystemStringFormat);
 var fieldInfo =
 systemStringFormatType.GetField("m_format", BindingFlags.NonPublic | 
BindingFlags.Instance);
 var formatString = fieldInfo?.GetValue(fmt) as string;
 hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(formatString ?? 
string.Empty));
 }
 else
 {
 var str = (loggingEvent.ExceptionObject ?? 
loggingEvent.MessageObject).ToString();
 hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(str));
 }

var builder = new StringBuilder();
 foreach (var b in hash.Take(2))
 {
 builder.Append(b.ToString("x2"));
 }

output = builder.ToString();
 }
 catch (Exception ex)
 {
 // can be found if log4net debugging is enabled
 Source.TraceError(ex.ToString());
 }

return output;
 }
 }

Sorry for the bad formatting (blame Atlassian).

I am reading SystemStringFormat.m_format by using reflection. That gives me the 
string template used when logging and it is the one I think is appropriate when 
outputting the type of the log message.

 

Now to my feature request: please expose the internals of SystemStringFormat so 
that I can do this in a safe way.

What do you think?

 

Regards,

Daniel Lidström

  was:
Hello

 

I'm trying to create a structured logging format and have a conversion pattern 
with a custom converter like this:

 

      <layout type="log4net.Layout.PatternLayout">

        <conversionPattern value="%date [%2thread] %-5level [%property\\{NDC}] 
%username - type=%message_checksum %message%newline" />

        <converter>

          <name value="message_checksum" />

          <type value="TestBed.MessageChecksumConverter" />

        </converter>

      </layout>

 

The interesting part of course is the message_checksum. For example, I am 
logging like this:

 

                Log.Debug("some debugging message");

                Log.Info(new \{ Id = 1, Name = "the name" });

                Log.InfoFormat("Logging msg \{0}", 1);

                Log.InfoFormat("Logging msg \{0}", 2);

                Log.InfoFormat("Logging msg \{0}", 3);

 

I would like the output to be something like this

 

2018-10-26 11:06:44,564 [ 1] DEBUG [(null)] XXX - type=f6d5 some debugging 
message

2018-10-26 11:06:44,638 [ 1] INFO  [(null)] XXX - type=e0e3 \{ Id = 1, Name = 
the name }

2018-10-26 11:06:44,648 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 1

2018-10-26 11:06:44,656 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 2

2018-10-26 11:06:44,663 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 3

 

As you can see, I am getting the type=32a6 for the last 3 logging messages. 
This allows me to search for all of those, regardless of the parameters given.

For example, I can now search and group the number of errors by their unique 
type and know which error is most common in our system.

 

To implement this, I did the following:

public class MessageChecksumConverter : PatternLayoutConverter
 {
 private static readonly TraceSource Source = new 
TraceSource(nameof(MessageChecksumConverter));
 private static readonly MD5 ChecksumGenerator = MD5.Create();

protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
 {
 var output = TryGetHash(loggingEvent);
 writer.Write(output);
 }

private string TryGetHash(LoggingEvent loggingEvent)
 {
 string output = string.Empty;
 try
 {
 byte[] hash;
 var fmt = loggingEvent.MessageObject as SystemStringFormat;
 if (fmt != null)
 {
 // read fmt.m_format and use that as input for hash
 var systemStringFormatType = typeof(SystemStringFormat);
 var fieldInfo =
 systemStringFormatType.GetField("m_format", BindingFlags.NonPublic | 
BindingFlags.Instance);
 var formatString = fieldInfo?.GetValue(fmt) as string;
 hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(formatString ?? 
string.Empty));
 }
 else
 {
 var str = (loggingEvent.ExceptionObject ?? 
loggingEvent.MessageObject).ToString();
 hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(str));
 }

var builder = new StringBuilder();
 foreach (var b in hash.Take(2))
 {
 builder.Append(b.ToString("x2"));
 }

output = builder.ToString();
 }
 catch (Exception ex)
 {
 // can be found if log4net debugging is enabled
 Source.TraceError(ex.ToString());
 }

return output;
 }
 }

{{}} 

{{Sorry for the bad formatting (blame Atlassian). }}

I am reading SystemStringFormat.m_format by using reflection. That gives me the 
string template used when logging and it is the one I think is appropriate when 
outputting the type of the log message.

 

Now to my feature request: please expose the internals of SystemStringFormat so 
that I can do this in a safe way.

What do you think?

 

Regards,

Daniel Lidström


> Expose members in SystemStringFormat
> ------------------------------------
>
>                 Key: LOG4NET-615
>                 URL: https://issues.apache.org/jira/browse/LOG4NET-615
>             Project: Log4net
>          Issue Type: Wish
>          Components: Layouts
>    Affects Versions: 2.0.8
>            Reporter: Daniel Lidström
>            Priority: Trivial
>
> Hello
>  
> I'm trying to create a structured logging format and have a conversion 
> pattern with a custom converter like this:
>  
>       <layout type="log4net.Layout.PatternLayout">
>         <conversionPattern value="%date [%2thread] %-5level 
> [%property\\{NDC}] %username - type=%message_checksum %message%newline" />
>         <converter>
>           <name value="message_checksum" />
>           <type value="TestBed.MessageChecksumConverter" />
>         </converter>
>       </layout>
>  
> The interesting part of course is the message_checksum. For example, I am 
> logging like this:
>  
>                 Log.Debug("some debugging message");
>                 Log.Info(new \{ Id = 1, Name = "the name" });
>                 Log.InfoFormat("Logging msg \{0}", 1);
>                 Log.InfoFormat("Logging msg \{0}", 2);
>                 Log.InfoFormat("Logging msg \{0}", 3);
>  
> I would like the output to be something like this
>  
> 2018-10-26 11:06:44,564 [ 1] DEBUG [(null)] XXX - type=f6d5 some debugging 
> message
> 2018-10-26 11:06:44,638 [ 1] INFO  [(null)] XXX - type=e0e3 \{ Id = 1, Name = 
> the name }
> 2018-10-26 11:06:44,648 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 1
> 2018-10-26 11:06:44,656 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 2
> 2018-10-26 11:06:44,663 [ 1] INFO  [(null)] XXX - type=32a6 Logging msg 3
>  
> As you can see, I am getting the type=32a6 for the last 3 logging messages. 
> This allows me to search for all of those, regardless of the parameters given.
> For example, I can now search and group the number of errors by their unique 
> type and know which error is most common in our system.
>  
> To implement this, I did the following:
> public class MessageChecksumConverter : PatternLayoutConverter
>  {
>  private static readonly TraceSource Source = new 
> TraceSource(nameof(MessageChecksumConverter));
>  private static readonly MD5 ChecksumGenerator = MD5.Create();
> protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
>  {
>  var output = TryGetHash(loggingEvent);
>  writer.Write(output);
>  }
> private string TryGetHash(LoggingEvent loggingEvent)
>  {
>  string output = string.Empty;
>  try
>  {
>  byte[] hash;
>  var fmt = loggingEvent.MessageObject as SystemStringFormat;
>  if (fmt != null)
>  {
>  // read fmt.m_format and use that as input for hash
>  var systemStringFormatType = typeof(SystemStringFormat);
>  var fieldInfo =
>  systemStringFormatType.GetField("m_format", BindingFlags.NonPublic | 
> BindingFlags.Instance);
>  var formatString = fieldInfo?.GetValue(fmt) as string;
>  hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(formatString ?? 
> string.Empty));
>  }
>  else
>  {
>  var str = (loggingEvent.ExceptionObject ?? 
> loggingEvent.MessageObject).ToString();
>  hash = ChecksumGenerator.ComputeHash(Encoding.ASCII.GetBytes(str));
>  }
> var builder = new StringBuilder();
>  foreach (var b in hash.Take(2))
>  {
>  builder.Append(b.ToString("x2"));
>  }
> output = builder.ToString();
>  }
>  catch (Exception ex)
>  {
>  // can be found if log4net debugging is enabled
>  Source.TraceError(ex.ToString());
>  }
> return output;
>  }
>  }
> Sorry for the bad formatting (blame Atlassian).
> I am reading SystemStringFormat.m_format by using reflection. That gives me 
> the string template used when logging and it is the one I think is 
> appropriate when outputting the type of the log message.
>  
> Now to my feature request: please expose the internals of SystemStringFormat 
> so that I can do this in a safe way.
> What do you think?
>  
> Regards,
> Daniel Lidström



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to