views:

80

answers:

2

So I've got this data access layer, and I also want to log to the database. In the spirit of eating my own dog food, I want to use my data access layer to do the logging. However, I also want to log the data access itself. Like so:

App
||
V
Log
||
V
Data=>Log

Am I at risk of getting into a feedback loop? If so, how should I avoid it? Could the references for the project loop onto each other and cause difficulty building? How have you successfully approached this (anti?) pattern in the past?

A: 

Create an assembly (or assemblies as the case may be) that only contain interfaces. Reference the interface only assembly from your concrete class assemblies and have every concrete class implement one or more interfaces. Do not have concrete class assemblies refer to other concrete class assemblies that are part of your solution.

This approach should help you avoid circular dependencies.

Implement a dependency injection/inversion of control container like StructureMap or one of the many other .NET options available to you to reduce coupling even further.

cfeduke
What about the idea of a feedback loop, whereby the DAL calls Log which calls the DAL and so on?
Chris McCall
I would suggest that all log messages should contain information about which component created the message. Then introduce a configurable mechanism in the DAL for controlling which components should generate logging, and then configure the log facility as one of the components which should not generate logs in the DAL.
Anton
I agree with the comment above, some consumers of the DAL should not cause the DAL to log. Maybe split up the DAL in an interface that includes logging (maybe this is the default to inject), and another interface that does not log. The interface that does log, redirects the actual call to the data access code to the interface that doesn't.
StephaneT
I have always just approached logging through the use of Log4Net. It helps solve the problem you cite in that it doesn't introduce it in the first place. Your domain goes through your DAL but does your logging specifically have to go through the same DAL? I prefer being able to log to a database, text log file, or other Log4Net providers. It isn't important that it goes through my DAL, its just important that it works reliably.
cfeduke
A: 

a possibly over-simplified solution:

public interface ILoggable {
    string ToLogFormat();
}

Then implement this interface on any object that can be logged. The logging layer now depends only on the interface, and can be used at any level.

an alternative is to use 'helper' classes to implement ToLogFormat via overloading, e.g.

public class LogHelper {
    public string ToLogFormat(DAO obj) { ... }
    public string ToLogFormat(SomeOtherClass obj) { ... }
    ...
}

you could use one monolithic log helper (which is bad, because it would have to reference every library) but a better solution might be to implement log helpers for each assembly or class and specify the name of the log-helper class using a custom attribute

personally, i prefer the ILoggable approach as being more flexible; your logging package could have a simple function in it like:

public class Logger {
    public string ToLogFormat(object obj) {
        if (obj is ILoggable) {
            return ((ILoggable)obj).ToLogFormat();
        }
        return obj.ToString();
    }
}
Steven A. Lowe