How do I insert tabs in the log4net layout pattern? - log4net

My need is simple - I want to be able to open my text log file in excel, so that it automatically breaks it in columns matching the log fields.
For that, I need the log fields separated with a tab.
My pattern is: %utcdate [%thread] %-5level %logger - %message%newline
I need something like:
%utcdate%tab[%thread]%tab%-5level%tab%logger%tab%message%newline
Thanks.

Caveat: I haven't actually used log4net. But if I understand correctly, the configuration is an XML file, isn't it? And the pattern is just text with some special tokens. So have you tried embedding actual tab characters in your pattern? The XML sequence for a tab is , e.g.:
<conversionPattern value="%utcdate [%thread] %-5level %logger %message%newline" />
Or if you're supplying the pattern some other way (perhaps via the PatternString constructor or whatever), just include tab characters in the string you're passing in. The docs for that constructor defer to the PatternLayout docs to talk about the string itself, and there they say:
You are free to insert any literal text within the conversion pattern.
(Their emphasis.) Worth a try, anyway...

This worked for me:
1) When your logging class is instantiated, add this line:
log4net.GlobalContext.Properties["tab"] = "\t";
2) Then in the log4net XML, make a reference to your newly-created log4net property. For example:
<conversionPattern value="%property{tab}%message%newline" />

You can type tab into pattern without escaping (see space between level and date):
<conversionPattern value="%level %date{HH:mm:ss,fff} ..." />
I cant write tab in visual studio, because it writes spaces, but I typed tab into notepad++ copy it (ctrl+c ctrl+v) and it is working.
EDIT: stack overflow replaced my tab with spaces. So you need to type your own tab

If this is just about Excel then you could use some other separator, maybe even a ; would be good enough.
Another option would be to write your own pattern converter. An example can be found here.

A tab in log4j2 pattern layout is: \t

Related

Sed Command: Searching pattern with wildcard before and after the target string

Content of sample.xml is like the one below.
<Name="com.name1.sample.date" level="ERROR"/>
<Name="com.name2.test" level="WARNING">
<Name="com.name3.type.yeah.trace" additivity="false" level="DEBUG">
I am trying to use sed and just replace the value of the "level paramater" on all lines.
However, using (*) as wildcard is not working for pattern matching.
I'd like the output to be like the one below.
<Name="com.name1.sample.date" level="INFO"/>
<Name="com.name2.test" level="WARN">
<Name="com.name3.type.yeah.trace" additivity="false" level="UPDATE">
Basically:
From this pattern
*level="<pattern>"*
To this pattern
*level="<updated>"*
Where the * could be any pattern.
I did some research here and was able to make it work for wildcard at the beginning but not at the end so I am doing a special handling for each pattern that has a different ending. Below is my code.
sed 's|="'"$logger_type"'".*|="'"$logger_type"'" level="'"$update_check"'"/>|g'
Where $logger_type is the name being referenced, and its level should be updated to whatever the content of $update_check
Basically:
From this pattern
*level="<pattern>"*
To this pattern
*level="<updated>"*
Since your input is line-oriented, we can use "logger_type" as an address regexp to process only the lines matching the regular expression; therewith we can simplify the substitution pattern to only specify level="…" and leave other attributes (like additivity) as they are.
sed /\"$logger_type'"/s/level="\w*"/level="'$update_check\"/ sample.xml

How to set a default value against an MDC key in log4j 2?

As in log4j we have an option to set a default value against an MDC key like this - mdc{key:-defaultVal}
Do we have something similar in log4j 2 ?
Looking in MdcPatternConverter it does not have support for default value.
There is open Jira ticket on that Tickt
I find that you can also use this: ${ctx:<key>:-<default_value>}
While there is no way to set a default with the %X pattern, there are the %equals and %equalsIgnoreCase patterns which can be used for something equivalent.
%equals{%X{<key>}}{}{<default>}
Offical Reference Logback link for Layout components.
X{key:-defaultVal}
If the specified Key value is null, then the default value specified after the :- operator is output.
If no default value is specified than the empty string is output.
It seems this must have changed at some point, as it is now possible to specify default values.
If you do something like org.apache.logging.log4j.ThreadContext.put("foo", "bar"); in your code, and then, in the log4j2 pattern, specify something like
<Pattern>%-5p [%t] %d [$${ctx:foo:-baz}] %c{1} - %m%n</Pattern>
You will see [bar] in the log messages generated by the same thread that the ThreadContext call was made, and you'll see [baz] in other threads.
Please note, (h/t to #Mahender Reddy Yasa in a comment above), you are able to specify ...[${ctx:foo}]... and it will print [bar] in the correct thread, but blank in the other threads - however, and I have no idea why, if you specify ...[${ctx:foo:-baz}]..., it will always print [baz] - You must use two dollar signs for it to get the correct behavior (e.g. ...[$${ctx:foo:-baz}]...
P.S. the brackets ([]) are not necessary, this is examples from my config

Using nlog replace layout renderer, replacement seems to be done twice instead of once

I'm attempting to use the NLog Replace Layout Renderer (https://github.com/NLog/NLog/wiki/Replace-Layout-Renderer). I want to use it to truncate over-long messages. It seems to be able to do so, but replacement happens twice rather than once.
In my nlog.config, I'm using the following:
<variable name="replaced_message" value="${replace:searchFor=.*:replaceWith=Replaced:regex=true:inner=${message}}"/>
<target name="filelog" xsi:type="File" fileName="${basedir}/../logs/webapp/${shortdate}.log"
layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}|${level:uppercase=true}|${machinename}|T:${threadid}|${logger}|${replaced_message}"/>
And I'm getting log entries like:
2015-03-04 13:41:14.337|INFO|T:11|ReplacedReplaced
Does anyone have an idea why the message is "ReplaceReplaced" rather than "Replaced"?
Turns out this problem has nothing to do with Nlog. It's just the regular expression that is the problem - identical to the problem found here:
Why does my Regex.Replace string contain the replacement value twice?
There are actually 2 matches to the regex ".*".
The * means match zero or more characters, so there are 2 matches - empty string, and the text.
Changing the pattern to ".+" instead of ".*" resolves the problem. ".+" means match one or more characters so it no longer matches the empty string.
This kinda messes with my head, but it does appear to work that way.
And by the way, just in case anybody was interested in doing the same thing as my original plan, to truncate the Nlog message to 500 characters, it can be done using the following in nlog.config:
<variable name="truncated_message" value="${replace:replaceWith=...TRUNCATED:regex=true:inner=${message}:searchFor=(?<\=.\{500\}).+}"/>
<target name="filelog" xsi:type="File" fileName="${basedir}/../logs/jobs/${shortdate}.log" layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff}|${level:uppercase=true}|${truncated_message}"/>

Prevent NLog from rendering inner text when layout render output is empty

I put the contents of my NLog error email text into a file and render it using a a FileContents renderer. What I'd like to do is hide certain parts of html output if a layout renderer produces an empty string
<div>Request ticket: ${httpContextItems:key=RequestTicket}</div>
I am not sure of the syntax of the when condition/property. Here are some attempts:
${httpContextItems:key=RequestTicket:when:length>0}
<div>Request ticket: ${httpContextItems:key=RequestTicket}</div>
${??? How to enclose? }
And NLog doesn't like this nested stuff:
${when:when=length(${httpContextItems:key=RequestTicket})=0:inner=<div>Request ticket: ${httpContextItems:key=RequestTicket}</div>}
I faced a similar problem and got things to work like this:
${when:when=length('${httpContextItems:key=RequestTicket}') > 0:inner=<div>Request ticket ${httpContextItems:key=RequestTicket}</div>}
Note that I had to drop the colon after Request ticket. NLog kept on cutting text before or after the colon, no matter what I tried (escaping with \, used ${literal}, replaced colon with its ASCII code, put the colon in a separate variable...).
And NLog doesn't like this nested stuff:
${when:when=length(${httpContextItems:key=RequestTicket})=0:inner=<div>Request ticket: ${httpContextItems:key=RequestTicket}</div>}
This was a bug in NLog due to the colon. This should work now since NLog 4.2, so the solution is, upgrade NLog. See this issue on GitHub

Appenwith and

My company's MySql database is riddled with fields named "system", so SubSonic's generated code clashes with the .NET System namespace.
I understand AppendWith appends a character(s) to the fields it indentifies as clashing with reserved words, but it doesn't seem to do anything in my case. Is there a way to see/update the list of reserved words it knows?
Same problem here:
AppendWith does only work for reserved keywords (eg. public etc.) not for namespaces.
That's how I solved the problem (look at the regexDictionaryReplace entry)
<add name="MyDataProvider"
type="SubSonic.MySqlInnoDBDataProvider, SubSonic"
connectionStringName="myConnectionString"
generateLazyLoads="true"
regexDictionaryReplace="[sS]ystem,SystemX;[tT]able[nN]ame,TableNameX"
fixPluralClassNames="false"
generatedNamespace="My.NameSpace"
removeUnderscores="false"
generateNullableProperties="false"
generatePropertyChangedEventHandler="true"
generateRelatedTablesAsProperties="true"
excludeTableList="audit"
tableBaseClass="ActiveRecord" />
You could try to use "stripTableText" to replace "system" with "". There are a lot of ways to do this and it even uses Regex if needed - have a look:
http://subsonicproject.com/configuration/config-options/

Resources