Situation is that level of log4net is configured as 'Error' but there is some information i need to write under a 'no matter what' condition
for example
"loggin has started"
if only 'Error' or 'Fatal' is enabled i cant log this in Error or Fatal since its just information
so is there any way i can do that other than change the level of the logger to info, write the log and then change back the level because that will act just like a workaround not a solution
and without using Headers since they only come at the beginning
EDIT: In an Appender
StringMatchFilter stringFilter = new StringMatchFilter();
stringFilter.AcceptOnMatch = true;
stringFilter.StringToMatch = "successfully";
stringFilter.ActivateOptions();
appender.AddFilter(stringFilter);
DenyAllFilter deny = new DenyAllFilter();
deny.ActivateOptions();
appender.AddFilter(deny);
adding to an appender and setting level 'All' to the root and managing levels in appenders but still i am unable to write any message containing 'successfully'
but please note when i set appender level to info the filter begins to work
I assume this is all because you don't like the idea of using .FatalFormat when it is not really an error.
I'm not sure how you would do this programatically, but if you were using a config file you add a section like
<logger name="ALWAYS">
<level value="DEBUG" />
appender-ref ref="RollingFileAppender" />
</logger>
which means you can log your messages like
log4net.LogManager.GetLogger("Always").InfoFormat( ... );
or you could create a static
static readonly log4net.ILog alwaysLogger = log4net.LogManager.GetLogger("Always");
and log via.
alwaysLogger.InfoFormat(....);
My suggestion would be to create a filter that looks first at a string match and then at the level. That way you could have a key string that you pass in the message (say "AppInfo" or something that would be unique and not found in an error). Then, your filter would pick that up and log it even when you logged it at the INFO level but the filter would ignore all other messages that weren't ERROR or FATAL. I wrote an article on CodeProject that will show you how to do complex filtering like this:
http://www.codeproject.com/KB/dotnet/Log4net_Tutorial.aspx
The one key here is that you would probably need to not specify the filtering in the root for this particular appender, since root supersedes the appender if I remember correctly.
Related
I want to log the request duration. For that, I have a middleware and on the OnActionExecuted I assign the time elapsed to a variable and try to register it using the Custom Layout Rendere through a lambda function
requestDuration = _stopWatch.ElapsedMilliseconds;
LayoutRenderer.Register("requestDuration", logEvent => requestDuration);
On my nlog.config I have the following
<column name ="RequestDuration" layout="${requestDuration}" quoting="Nothing"/>
NLog complains saying that this will be ignored:
Error Error parsing layout requestDuration will be ignored. Exception: System.ArgumentException: LayoutRenderer cannot be found: 'requestDuration'
at NLog.Config.Factory`2.CreateInstance(String itemName)
at NLog.Layouts.LayoutParser.GetLayoutRenderer(ConfigurationItemFactory configurationItemFactory, String name)
Am I registering the layoutRenderer at the wrong place?
Please note that I'm trying to have a column that is the request duration, and not simply writing that time on the log message
If you get "LayoutRenderer cannot be found" while you have registered your layout renderer, then NLog parsed the config before the layout register.
You could do a reinitialize after the register:
LogManager.Configuration = LogManager.Configuration.Reload();
Although registering earlier is better.
Please note that it looks like a custom layout renderer for this case isn't really needed. There are a lot of context options for this, see https://github.com/NLog/NLog/wiki/Context
Let's say I have this partial configuration, with NLog:
<rules>
<logger name="ExistsInConfig" writeTo="Console"/>
</rules>
..and then I write this code:
var configuredLogger = LogManager.GetLogger("ExistsInConfig");
configuredLogger.Log(LogLevel.Info, "hello, cruel world!");
var missingLogger = LogManager.GetLogger("NotInConfig");
missingLogger.Log(LogLevel.Info, "goodbye, cruel world!");
In the console output I will see only the first logging statement, because the second named logger was not found in the config file.
How can I programatically detect that the second logger was not found, and therefore will produce no output?
If you have the instance of Logger, you could ask it to it:
bool hasConfigRuleForInfo = missingLogger.IsEnabled(LogLevel.Info)
If not, then you need some tricks, some possibilities:
or create your own LogManager class remember which remembers which loggers are used
or read with reflection the private propertiy LogManager.factory.loggerCache (not supported of course ;))
add a wildcard( *) rule to your config (API or XML) and write to MemoryTarget or a Custom Target. This could effect your performance. PS. with ${logger} you get the logger name. You will also need the final option on other rules.
I think this is the best way:
if (!NLog.LogManager.Configuration.ConfiguredNamedTargets.Any(t => t.Name.Equals("NameToValidate")))
{
//config not found
}
With #Julian 's answer, you could have the Config you are looking for but not the level you are comparing within. You could even have the Config without any level activated in your NLog config.
In those cases you would get an incorrect check response.
I'm using NLog to send emails when an exception occurs in my app. Here's a portion of my target :
<target xsi:type="Mail"
name="email"
subject="${level}:" .. >
I receive emails with subjects like "Error:" or "Fatal:". This works fine but I want to add the Exception.Message to the subject of the email
Is it possible to setup custom properties in NLog. I can't find out how to do this, so just to make it clear what I want here is an example of the kind of thing I'm trying to do :
m_oLogger.Fatal( oException.BuildMessage(), new {MyMessage=oException.Message});
*Note that BuildMessage() is just an extension method to convert the full exception details (including inner exceptions) to a readable string
And in my target :
<target xsi:type="Mail"
name="email"
subject="${level}: ${Custom.MyMessage}" .. >
Then I would get emails with the subjects like :
Fatal: Syntax error in parameters or
arguments. The server response was:
Account does not exist
Is this kind of flexibility possible with NLog? If not, do you know of another .NET logging platforms that offers this kind of functionality?
In general instead of creating custom layoutRenderer suggested by wageoghe it's possible to use EventContext-Layout-Renderer that allows to pass any number of custom properties
LogEventInfo theEvent = new LogEventInfo(LogLevel.Debug, "", "Pass my custom value");
theEvent.Properties["MyValue"] = "My custom string";`
log.Log(theEvent);
and in your NLog.config file:
${event-context:item=MyValue} -- renders "My custom string
For the particular https://github.com/nlog/NLog/wiki/Exception-Layout-Renderer the format should be
${exception:format=message}
It is very easy to add a custom LayoutRenderer to NLog. See my first answer to this question for an example of a LayoutRenderer that allows you to add the System.Diagnostics.Trace.CorrelationManager.ActivityId value to your logging output.
To do what you want, you probably don't need a custom LayoutRenderer. If you want to send an email whose subject is the log leve PLUS the Message property of the exception, you should be able to configure something like this:
<target xsi:type="Mail"
name="email"
subject="${level}: ${exception.Message}" ..>
That should create the subject of the email by concatenating the level and the value of the Exception.Message property. You will have to call the logging overload that takes an Exception as a parameter.
Does this help?
This is likely impractical: I'm fairly sure the NLog framework doesn't have reflection as a part of its logging format [to do so would require NLog to have some sort of concept of where your referenced assemblies are and what their type is.]
Can you simply do all your message parsing/formatting in the C# code, and and pass it as a part of the already existing variables? They list a lot of these in the Mail-target NLog documenation.
I'm looking for a walkthrough on how to create and use a custom provider for ASP.Net Healthmonitoring.
So far I've only worked with the e-mail provider that generates e-mails on errors. Basically I want to do the same, but with more flexibility:
I want to use the HealthMonitoring features (I don't want to use the Application_OnError event in the global.asax) in a way that allows me have access to an event, that gets thrown like "OnNewHealthMonitoringEntry" with all the information provided in the e-mail, to run custom code.
Edit:
Based on the source code provided here http://www.asp.net/general/videos/how-do-i-create-a-custom-provider-for-logging-health-monitoring-events I was able to build my own custom provider and implement it. Now I want to add some new attributes to configure my custom provider.
Here is what the web.config looks like:
<healthMonitoring>
<bufferModes>
<add name="Log Notification" maxBufferSize="1" maxFlushSize="1" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:00:10"/>
</bufferModes>
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
<profiles>
<add name="Custom" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"/>
</profiles>
<rules>
<add name="File Event Provider" eventName="All Errors" provider="FileEventProvider" profile="Custom"/>
</rules>
</healthMonitoring>
If I attempt to add an attribute to the provider, like this
<providers>
<add name="FileEventProvider" buffer="true" bufferMode="Log Notification" foo="bar" type="healthmonitoringtest.FileHealthMonitorEventProvider"/>
</providers>
I'll get an error saying:
An exception of type
'System.Configuration.ConfigurationErrorsException'
occurred in System.Web.dll but was not
handled in user code Additional
information: Unexpected attribute foo
in the configuration of the
FileEventProvider.
Is it possible to store configuration necessary for custom provider close to the healthMonitoring section? I guess I could include the settings into the appSettings node, but I'd like to configure it somehow with attributes (inside the healthMonitoring node). Is that possible?
Edit2:
You might take a look at this article: http://www.tomot.de/en-us/article/6/asp.net/how-to-create-a-custom-healthmonitoring-provider-that-sends-e-mails
The following series of articles will take you through the basics of using the Health Monitoring System upto creating Custom Events.
Then the following 26 minute video will take you through creating a custom provider that records events to a text-based log file.
UPDATE Based on Comment
Looking at your update and using Reflector to look at the source for the BufferedWebEventProvider class that you base your custom provider on, I have found that the Initialize method in BufferedWebEventProvider does a check at the end to see if there are any attributes that it doesn't recognize. This is done by removing values from the config NameValueCollection parameter as soon as they are assigned to the properties or fields of the BufferedWebEventProvider. Then a check is done to see if the config parameter is empty and if not that means that there are extra attributes added, which causes an exception to be thrown.
As to how to fix this problem, one option is to:
Move the call to base.Initialize to the end of the method
Remove the additional attributes as soon as you assign them to variables just like the provider does.
Something like the following would work:
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
foo = config["foo"];
if (String.IsNullOrEmpty(foo))
{
// You can set a default value for foo
}
//remove foo from the config just like BufferedWebEventProvider with the other
//attributes. Note that it doesn't matter if someone didn't proivde a foo attribute
//because the NameValueCollection remains unchanged if you call its Remove method
//and the name doesn't exist.
config.Remove("foo");
base.Initialize(name, config);
}
Hopefully this works out for you.
I need to change the app name based on what configuration I'm using in Visual Studio. For example, if I'm in Debug configuration, I want the app name to show as 'App_Debug' in the Application field in the Elmah_Error table. Does anyone have any experience with this? Or is there another way to do it?
This can now be done purely in markup. Just add an applicationName attribute to the errorLog element in the <elmah> section of the web.config file. Example:
<errorLog type="Elmah.SqlErrorLog, Elmah"
connectionStringName="connectionString" applicationName="myApp" />
I've tested this and it works both when logging an exception and when viewing the log via Elmah.axd.
In the case of the OP, one would imagine it can be set programatically too but I didn't test that. For me and I imagine for most scenarios the markup approach is sufficient.
By default, Elmah uses the AppPool's application GUID as the default application name. It uses this as the key to identify the errors in the Elmah_Error table when you look at the web interface that's created through it's HTTP Module.
I was tasked to explore this option for my company earlier this year. I couldn't find a way to manipulate this by default since Elmah pulls the application name from HttpRuntime.AppDomainAppId in the ErrorLog.cs file. You could manipulate it by whatever key you want; however, that is the AppPool's GUID.
With that said, I was able to manipulate the ErrorLog.cs file to turn Elmah into a callable framework instead of a handler based one and allow for me set the ApplicationName. What I ended up doing was modifying ErrorLog.cs to include a property that allowed me to set the name as below:
public virtual string ApplicationName
{
get
{
if (_applicationName == null) { _applicationName = HttpRuntime.AppDomainAppId; }
return _applicationName;
}
set { _applicationName = value; }
}
What you will probably need to do is adjust this differently and set the ApplicationName not to HttpRuntime.AppDomainAppId but, instead, a value pulled from the web.config. All in all, it's possible. The way I did it enhanced the ErrorLog.Log(ex) method so I could use Elmah has a callable framework beyond web applications. Looking back I wish I did the app/web.config approach instead.
One thing to keep in mind when changing the application name in Elmah. The http handler that generates the /elmah/default.aspx interface will no longer work. I'm still trying to find time to circle back around to such; however, you may need to look into creating a custom interface when implementing.