NLog: Limit Logger Names to Enum or other structure - c#

I am using NLog for some logging and thanks to these answers:
Getting Logger Name into Excel file with NLog
https://stackoverflow.com/questions/50123661/nlog-in-c-sharp-with-severity-and-categories?noredirect=1#comment87344565_50123661
I am able to log different types of events (ex: "Thermal", "Database",etc.) to a single file with the logger field showing the type of event. One simply calls for example:
NLog.LogManager.GetLogger("Database").Debug("Error writing to DB");
This all works fine and might be enough. However, you'll notice that any programmer is free to put any name they want in GetLogger AND misspell it. "GetLogger("Datobuse"). It would be nice if the programmer had to choose from an enum or other structure:
NLog.LogManager.GetLogger(LoggerNames.Database).Debug("Error writing to DB");
This seems like it might be a common problem and might already have an elegant solution. I can imagine overriding the LogManager class but am not sure of the specifics. Note that LogManager is a public static class in the NLog library so not clear how to hide it. Also, there is the nice property that if you fill in the config file once in your app project, the config file works perfectly for all the projects in the solution as long as you include NLog as a reference.
I'll go down the path of creating a library project that makes use of NLog library and then include that it my main project UNLESS there is already a great solution. I'm betting there is, but haven't seen one.
Thanks,
Dave

If you have "global" logger names, then the easy solution is just to use global logger instances.
The same global NLog Logger instance can be used by multiple locations without getting into threading issues.

Related

Get application settings without file access

I have an app.config which is working fine.
But I also have a tool for automated testing, that runs some tests in environment without any file access. So I have to read a config file from string (or memory stream), but without mapping it physically because there is no access to file system from this automatic testing process.
In real life, of course, config file is stored somewhere, but for automated testing purposes I need some workaround to read a config file from string stored in memory. Is it even possible? I googled a lot, but the only thing I found is Save it as temp file and then read, but it's not my case.
Avoid a direct dependency from your class on app.config or any other file. Your class doesn't need app.config or Properties.Settings. It needs the values contained in the those files..
If you create a workaround for testing purposes then you're testing a different version of your class. That's the inherent problem - direct dependency on these files isn't testable. It doesn't mean that they're bad in some way or that we shouldn't use them, only that the class that requires the values should not read them from the file.
An ideal solution is constructor injection, a form of dependency injection. Provide the value to the class in its constructor and store it as a field. That way when the class is created it always has the values it needs.
At runtime you can use a dependency injection container - here's a walkthrough on setting one up for WCF. You're likely in a different project type, but the concepts still apply.
But for testing, it's as easy as creating a class and passing whatever value you want to use into the constructor. It's impossible to test with different values when the class reads from settings but it's easy using constructor injection.
Without the configuration file you'll have the default settings. You may override the default values:
Properties.Settings.Default["PropertyName"] = NewPropertyValue";
(Set the correct access modifier on your Settings class and use the correct namespace if it is in a library)
As first option I would go for Settings file in your case.
Even your user won't be ablle to access settings file content. Then it will return a default value for a particualr property.
You can try creaty a silly console app
static void Main(string[] args)
{
Console.WriteLine(Settings.Default.MyProperty);
Console.ReadLine();
}
were you set the your value for MyProperty on the Settings Tab of you Project Properties.
Then you can build your solution, open the binaries folder and delete your exe.config file and you will see that the app will be use default values.
As second option you can use command line arguments. could also be an option for you. (Here the article about some tricky case for command line arguments Backslash and quote in command line arguments )
Third option could be placing your file at c:\users\your app user \AppData\Roaming\YourAppName folder. here you should be granted for file access even for restricted user
For education reason I would also reccomend to look at this article: https://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(ApplicationSettingsOverview);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5)&rd=true
Maybe you find the "Load Web Settings" option nice.
Another palce for investigation could be

Wrong app config file?

I have a class library that has a function with this code:
this.apikey = ConfigurationManager.AppSettings["ApiKey"];
When I call this function in a console application, it says AppSettings has no keys. also it states the connection string is aspnet... whereas mine is sqlserver. So it is certainly not reading my library app config even though Im calling that in a library function.
Is this normal or am I doing something wrong?
I was hoping to avoid having to make and parse an xml and reinvent the wheel.
Thanks
Is this normal or am I doing something wrong?
It is normal and you are doing something wrong.
A library does not, usually, have its own configuration - it is subject to the configuration of the running application.
If you add your appSettings and connectionStrings to the application configuration all will work.
In other words, when an application loads and the libraries it uses are loaded, the application configuration is read - no other configuration file is read. When calling the static methods of ConfigurationManager, the loaded configuration is what's in effect.
There are ways to load specific configuration files, but that's not the default behaviour.
You are certainly wrong at some place. May be you have written your keys in different section than the appSettings. Just check it, and if it is correct then , you will need to reinvent the wheel as below:
XDocument.Load(HttpContext.Current.Server.MapPath("~/web.config"));
Be sure to add System.Web namespace to your project before using HttpContext

Error logging sample project

I need to create a Error logging project from scratch in C#.
I would like to save to a file with several levels, this logging project I am taking as an assignment from which I can learn many things and want to build it as small loggin utility for now.
I saw few loggin project which has singleton pattern and a config file having some entries and also in the consuming application config - some references of logger proj interface are there
can some one please give me an idea as how can I create a new logger
proj from scratch and what is the purpose of having entries in
config ?
pseudo code for logger project or any link
Thanks in advance.
Instead of implementing your own logging mechanism you may want to check whether existing components are an option. For example log4net is a frequently used framework that people use for .NET based projects.
Also, the Logging Application Block from Microsoft:
http://msdn.microsoft.com/en-us/library/ff632023.aspx
http://msdn.microsoft.com/en-us/library/ff664569(v=PandP.50).aspx
There are several key elements you need to consider before making one from scratch. Just to name what comes to my head :
How do you want to log? Do you want to save logs to a file, in a database, to send mails, just to have the logs shown in a console?
If you persist the logs, do you want to log everything, forever, or you want a "rolling" X lines to be kept, the rest discarded?
Do you want to have several level of logs? For example, you could log some things Info, Warning, Error, Critical Error, etc.
Do you want your logging library to support custom formatting for the logs?
As for the question about the config, it's really something you want to do. If you're talking about the app.config files, it allows you to can change the configuration of your application without rebuilding it. It can also provide some default parameters the user can override. By user, I mean another developer using your library.

What is the best way to create a log for each instance of a class in log4net?

We have a couple of long lived objects each of the same class in the system. There are only about 5 or 6 and they are connections to outside systems. I want each of those instances to have their own file that they can log to.
What is the best way to do this? I can only see adding loggers programatically as the answer right now.
UPDATE:
I want to avoid using the configuration file because if I add a new connection to a different remote host then i want its log output to go to file named after the connection without having to first hack around in a config file. It would be nice if it was done automagically. I don't know maybe this can be achieved in a config file once off and that you don't need to edit it everytime.
The best answer IS programatical logging, i went through the same problem and found it as the only solution.
For more help check this question (mine)
StackOverFlow Question posted by me
and i thing yours and my problem are the same, dynamic loggers, re create loggers, dispose loggers and all that stuff at runtime :)
if any more questions, do ask, will be glad to help since i have gone through all that :)
I can actually see a couple of possibilities:
Assign each logging to a different category for each connection and append logs for each category to different files.
Create new loggers programmatically as you suggested.
Use dependency injection to inject as many separate logger as you need.
I have an article that might help:
http://horth.com/blog/?p=165
This is about changing a logfile at runtime. What you could do is pass in the file name for each instance into your log4net file. That way you could create a log file for each instance of your class.
As for your edit about not wanting to use a config file, this method gets around that issue so that you can use a config file but still have the flexibility you want.

Create custom logger, should I extend class from log4net

I am doing something unusual.
I have an application, it runs as a windows service.
what it does is that, it monitor one folder, when ever there is some new file put into that folder, the application will do something to the file.
Whenever there is an error when processing one file. I need to create a text file, and put the error/exception information into that text file. (later i can do something with this file)
so there is something like this
FileWatch, when there is a new file, do following :
try
{
processing file
}
catch(Exception ex)
{
MyLogger write exception message into one new text file
}
So far how i did it is that. I create a class for example MyLogger, whenever i new one MyLogger, it creates a text file (the name matters, need to be a specific format), and there is one method in side MyLogger "WriteError(string message)", it writes text into that file.
Since i used log4net in my application. Do you think i should modify my logger, to extend some class from log4net, so that i can get some benefit? (not sure what kind of benefit i will get, but log4net is a good logging framework, the way it handle text file might have thing that i do not aware)
Thanks
log4net or any other generic logger is helpful if
1) you want to have a consistent logging facility in many places across your application; and/or
2) you want the ability to customize logging format, level and so on.
From your description it sounds like there is a single point in your app where you need to log the exception in a specific way. If this is correct, you will probably gain no benefit from creating a custom logger - just write a method that logs exception to a file in the way you need.
If I misunderstood you, and there is a need for generic logger (that is, either 1) or 2) above is true), extending log4net by inheriting a logger or creating a wrapper is fine.
I've created log4net wrappers before. I find it handy to start this way as you don't always know what the logging requirements are at the start of a project. My rule has been that the log4net library can only be referenced from my own "logging" namespace. This way, the application code only calls the wrapper, and the wrapper is the only point of contact to the log4net functionality.
In the long run, it's probably worth investing in building your own logger. If you encapsulate log4net properly, you should be able to make this upgrade rather easily, without having to change your code.
Why not use Trace Listeners from the .NET framework? They provide many of the benefits of a logging network, without the need to incorporate an external framework.
Benefits include centralized log management and the ability to direct the output logs to one or more sources such as a console window, text file, or the Windows Event Log.
You should spend some time creating your own logger that does exactly what you want. This would be the best way. Is also fairly easy and you have full control on the customization so you can make the output look and feel as in log4net. You could Google for logging sample and start modifying that one.
I am not sure if I would use a log framework for this purpose. I have the impression that writing this text file in the exception case is part of your business process. Logging serves a different purpose that can be turned off without affecting business processes...

Categories