Elegant way to log actions? - java

Say you have an application with a series of actions. How would you write it such that actions are logged when they are triggered?
Use a Template pattern.
Use AOP.
Use a Listener and Events.
Use a combination of the above.
Something else (explain).

I'd vote for AOP for the sake of eliminating redundancy, but only if there's room for AOP in your project.
You can have custom logging using a logging library from your methods elsewhere in your project, but in a particular component where you hold many similar classes and want to log similar things for all of them, it can be painful to copy/paste and make sure everyone knows how to log.
EDIT: regarding the other enumerated approaches, I think the advantage of AOP would be that it doesn't require you to design your code (template methods or events) specifically for this topic. You usually don't lose any of the code flexibility when spotting cross-cutting concerns and treating them as such, as opposed to redesigning a whole class hierarchy just to make use of consistent logging.

I think the best answer is using log4j (or sli4j, if that's the latest) inside an aspect.
Logging is the "hello world" of AOP. If you aren't using AOP, you're doing it wrong.

It really would depend on your specific context. Specifically on what was being tracked and how the application currently worked. If the actions are classes that all have a common base class and all you care about is the name of the action, then a simple addition to log in this class would be a great choice. If you have actions spread across several layers of code, then an AOP or Listener/Event type solution might work better. If that application was a web app vs desktop or if you ultimately need the logs feed to a database, webservice, or just want text files all make a difference.

if you simply want to log particular actions it's probably simplest to use a logging api such as commons-logging or log4j etc add a log statement in the code you wish to track.

Related

Logging and Dependency Injection

I try to build and application based on Java.
For dependency injection I use Google Guice.
Now I came up with the problem of logging some information during the application. I do not talk about general logging in a way of method calls etc. I know about AOP and that I can do like method call tracing etc. with that.
What I look for is manual logging. I need some way of logging in nearly each class in my application. So I thought about two options:
getting the logger by using the Guice injection framework doing this for me through the constructor (or setter or private ...) but it feels like adding the logging concern really to each class and pollutes my constructor
using a global service locator in the method where I want to call the log. Uhh but all DI fans will hate me for doing that
So what is the best way from a practical point of view?
I need some way of logging in nearly each class in my application.
Think again. If you think you need logging in nearly every class, your design might be sub optimal and might cause maintenance issues in the long run. This Stack Overflow answer talks about what's the issue and how to improve it. It's answered in the context of .NET, but the answer is applicable to Java as well.
That answer mainly talks about exception logging, for non-exception logging I would say: Prevent logging too much information at too many places. For each info or warning that you want to log, question whether this shouldn't have been an exception in the first place. For instance, don't log things like "we shouldn't be in this branch", but throw an exception!
And even when you want to log debug information, does anyone ever going to read this? You'll end up with log files with thousands and thousands of lines that nobody ever reads. And if they read it, they have to wade through all those lines of text and do complicated regex searches through it to get the information they were looking for.
Another reason I see developers do this is to cover up for their used coding practices. Just as comments are used in this way. I see developers log things like "we have executed this block" or "this if branch skipped". This way they can trace through the code and big methods.
However, instead of writing big methods, we all know by now that methods should be small. No, even smaller. Besides, if you unit test your code thoroughly, there is not much reason to debug the code and you have verified that it does what it is supposed to do.
And again good design can help here. When you use a design as described in that Stack Overflow answer (with command handlers), you can again create a single decorator that can serialize any arbitrary command message and log it to disk before the execution starts. This gives you an amazingly accurate log. Just add some context information (such as execution time and user name) to the log and you have an audit trail that could even be used to replay commands during debugging or even load testing.
I use this type of application design for a couple of years now, and since then, I hardly ever have any reason to do extra logging within the business logic. It is needed now and then, but those cases are pretty rare.
but it feels like adding the logging concern really to
each class and pollutes my constructor
It does, and you'll end up with constructors with too many parameters. But don't blame the logger, blame your code. You are violating the Single Responsibility Principle here. You can 'hide' this dependency by calling it through a static facade, but that doesn't lower the number of dependencies and overall complexity of a class.
using a global service locator in the method where I want to call the log. Uhh but all DI fans will hate me for doing that
In the end, you will hate yourself for that, because every class is still has an extra dependency (a well hidden dependency in this case). This makes each class more complicated, and will force you to have more code: more code to test, more code to have bugs, more code to maintain.
The topic of logging and how one should go about it is actually a more complex topic than one might at first think.
As with many questions, the answer to how one should approach logging is "It depends". There are certainly some use cases which can be mitigated without the need of components taking on a logging dependency. For example, a need to uniformly log all method calls within a library can be addressed with the Decorator Pattern and superfluous uses of logging exceptions can be addressed by centralizing such logging at the top of a call stack. Such use cases are important to consider, but they don't speak to the essence of the question which really is "When we would like to add detailed logging to a component in strongly-typed languages such as Java and C#, should the dependency be expressed through the component's constructor?"
Use of the Service Locator pattern is considered to be an anti-pattern due to the fact that it's misuse leads to opaque dependencies. That is to say, a component which obtains all its dependencies through a Service Locator doesn't express everything that's needed without knowledge of the internal implementation details. Avoiding the Service Locator pattern is a good rule-of-thumb, but adherents of this rule should understand the when and why so as not to fall into the cargo cult trap.
The goal of avoiding the Service Locator pattern is ultimately to make components easier to use. When constructing a component, we don't want consumers to guess at what is needed for the component to function as expected. Developers using our libraries shouldn't have to look at the implementation details to understand which dependencies are needed for the component to function. In many cases, however, logging is an ancillary and optional concern and serves only to provide tracing information for library maintainers to diagnose issues or to keep an audit log of usage details for which the consumers are neither aware or interested. In cases where consumers of your library must provide dependencies not needed for the primary function of the component, expressing such dependencies as invariant (i.e. constructor parameters) actually negates the very goal sought by avoiding the Service Locator pattern. Additionally, due to the fact that logging is a cross-cutting concern (meaning such needs may be widely desired across many components within a library), injecting logging dependencies through the constructor further amplifies usage difficulty.
Still another consideration is minimizing changes to a library's surface-area API. The surface-area API of your library is any public interfaces or classes required for construction. It's often the case that libraries are constructed through a DI container, particularly for internally-maintained libraries not meant for public consumption. In such cases, registration modules may be supplied by the library for specific DI containers or techniques such as convention-based registration may be employed which hide the top level types, but that doesn't change the fact that they are still part of the surface-area API. A library which can easily be used with a DI container, but can also be used without one is better than one which must be used with a DI container. Even with a DI container, it's often the case with complex libraries to reference implementation types directly for custom registration purposes. If a strategy of injecting optional dependencies is employed, the public interface is changed each time a developer wants to add logging to a new type.
A better approach is to follow the pattern established by most logging libraries such as Serilog, log4net, NLog, etc. and obtain loggers through a logger factory (e.g. Log.ForContext<MyClass>();). This has other benefits as well, such as utilizing filtering capabilities by each respective library. For more discussion on this topic, see this article.

Introduce per-customer personalization in java application

I've searched on internet and here on SO, but couldn't wrap my mind around the various options.
What I need is a way to be able to introduce customer specific customization in any point of my app, in an "external" way, external as in "add drop-in jar and get the customized behavior".
I know that I should implement some sort of plugin system, but I really don't know where to start.
I've read some comment about spring, osgi, etc, can't figure out what is the best approach.
Currently, I have a really simple structure like this:
com.mycompany.module.client.jar // client side applet
com.mycompany.module.server.jar // server side services
I need a way of doing something like:
1) extend com.mycompany.module.client.MyClass as com.mycompany.module.client.MyCustomerClass
2) jar it separately from the "standard" jars: com.mycompany.customer.client.jar
3) drop in the jar
4) start the application, and have MyCustomerClass used everywhere the original MyClass was used.
Also, since the existing application is pretty big and based on a custom third-party framework, I can't introduce devastating changes.
Which is the best way of doing this?
Also, I need the solution to be doable with java 1.5, since the above mentioned third-party framework requires it.
Spring 3.1 is probably the easiest way to go about implementing this, as their dependency injection framework provides exactly what you need. With Spring 3.1's introduction of Bean Profiles, separating concerns can be even easier.
But integrating Spring into an existing project can be challenging, as there is some core architecture that must be created. If you are looking for a quick and non-invasive solution, using Spring containers programmatically may be an ideal approach.
Once you've initialized your Spring container in your startup code, you can explicitly access beans of a given interface by simply querying the container. Placing a single jar file with the necessary configuration classes on the classpath will essentially automatically include them.
Personalization depends on the application design strongly. You can search for a pluggable application on the Internet and read a good article (for an example: http://solitarygeek.com/java/a-simple-pluggable-java-application). In the pluggable application, you can add or remove a feature that a user decides. A way for the pluggable application is using the Interface for de-coupling of API layer and its implementation.
There is a good article in here
User personalisation is something which needs to be in the design. What you can change as an after thought if the main body of code cannot be changed, is likely to be very limited.
You need to start be identifying what can be changed on a per user basis. As it appears this cannot be changed, this is your main limiting factor. From this list determine what would be useful to change and implement this.

Advantage in using Java Logger?

I want to log information to a file and want to know is there any advantage in using the Java Logger class versus my own personal method of logging?
I know using a logger I just add my own FileHandler to the logger. My personal method is just using a FileOutputStream.
Honestly your logger may be as good, it's pretty easy to put in log levels, filtering, etc.
The problem is when you start to put together code from 10 different groups each with their own logging. Some use System.out, some use some custom logger, some use log4j, ...
How do you parse or redirect the output? How do you filter all that output to just show your messages (For instance, filtering options in log4j won't prevent messages being sent straight to System.out).
It's a pretty big bulk change depending on which system you are moving from/to. Better just to use one very common one from the beginning and hope that it's the one everybody else on the project chooses.
The real question is: why would you bother writing your own logger when there are already existing libraries for doing that? Does your logger do something that the others don't? I kind of doubt it.
Standardization is another big issue - see Bill K's answer.
For most scenarios, a standard logging framework is the way to go. They are pretty flexible. But using your own implementation can also be a valid option, specially if we are not speaking of traditional logging (global debugging, problems, warning messages) but about specific informational meesages or accounting.
Among other factors, bear in mind that the standarization of logging allows third party libraries to cooperate. For example, if you have a standard web application using (say) Hibernate, and you have configured a standard Java logging lib, then you can not only log from your own code but also tell Hibernate to log debugging info to your log files (not necessarily the same files). That is very useful - almost a must.
If you code your own logging library with a plain FileOutputStream, you must decide -among other things- if you are going to keep the file opened, or reopen-append-close in each write - and you must take of synchronization and related issues. Nothing terribly complicated, though.
The logger gives to ability to define different levels of importance of the logged messages and the ability to use different sink for the output - the console, a file, etc.
Also it's easy to enable or disable only some type of message when using a logger - for example you don't want to see every debug message in production.
A logging framework allows you specify logging levels (e.g. log only critical messages, log only debug messages etc.). It also allows you to log to multiple destinations (e.g. to a file, to syslog etc.) and you can do this even after your application is fully built by just changing a config file and not changing any code. It can also format your logs easily depending on various parameters.
There are numerous other advantages since proper logging is a rather involved problem and these packages have been written to solve them. I think the important question, why would you not use them?
Well I would always prefer tested thing and approved by community over something which still need a lot of test. Logger allows you many things which will consume you some time to implement and to test the robustness of your solution. A big plus will be the know-how of the next person who will do something with your code, in case it will be your logger, normally it would take more time to learn how its working out, since there is much more examples and documentation for java.util.logger.
Like all others mention, there are more advantages to using a more common logging system over writing your own. To be honest, the Java util logging api is not nearly as extensive and configurable as other libraries you might find out there on the internet.
Bare in mind that rolling your own always has the disadvantage of being less tested and therefore more prone to break or skip some potentially crucial messages.
Personally I prefer using SLF4J since it allows me to plug in adapters for more commonly used logging frameworks and then let's me pick my own actual logging implementation, this solves most of the problems with different library writers preferring different logging frameworks. And if you consider yourself up for the task you could writer an implementation for SLF4J yourself ;)

Java Dependency injection: XML or annotations

Annotations becoming popular. Spring-3 supports them. CDI depends on them heavily (I can not use CDI with out of annotations, right?)
My question is why?
I heard several issues:
"It helps get rid of XML". But what is bad about xml? Dependencies are declarative by nature, and XML is very good for declarations (and very bad for imperative programming).
With good IDE (like idea) it is very easy to edit and validate xml, is not it?
"In many cases there is only one implementation for each interface". That is not true!
Almost all interfaces in my system has mock implementation for tests.
Any other issues?
And now my pluses for XML:
You can inject anything anywhere (not only code that has annotations)
What should I do if I have several implementations of one interface? Use qualifiers? But it forces my class to know what kind of injection it needs.
It is not good for design.
XML based DI makes my code clear: each class has no idea about injection, so I can configure it and unit-test it in any way.
What do you think?
I can only speak from experience with Guice, but here's my take. The short of it is that annotation-based configuration greatly reduces the amount you have to write to wire an application together and makes it easier to change what depends on what... often without even having to touch the configuration files themselves. It does this by making the most common cases absolutely trivial at the expense of making certain relatively rare cases slightly more difficult to handle.
I think it's a problem to be too dogmatic about having classes have "no idea about injection". There should be no reference to the injection container in the code of a class. I absolutely agree with that. However, we must be clear on one point: annotations are not code. By themselves, they change nothing about how a class behaves... you can still create an instance of a class with annotations as if they were not there at all. So you can stop using a DI container completely and leave the annotations there and there will be no problem whatsoever.
When you choose not to provide metadata hints about injection within a class (i.e. annotations), you are throwing away a valuable source of information on what dependencies that class requires. You are forced to either repeat that information elsewhere (in XML, say) or to rely on unreliable magic like autowiring which can lead to unexpected issues.
To address some of your specific questions:
It helps get rid of XML
Many things are bad about XML configuration.
It's terribly verbose.
It isn't type-safe without special tools.
It mandates the use of string identifiers. Again, not safe without special tool support.
Doesn't take any advantage of the features of the language, requiring all kinds of ugly constructs to do what could be done with a simple method in code.
That said, I know a lot of people have been using XML for long enough that they are convinced that it is just fine and I don't really expect to change their minds.
In many cases there is only one implementation for each interface
There is often only one implementation of each interface for a single configuration of an application (e.g. production). The point is that when starting up your application, you typically only need to bind an interface to a single implementation. It may then be used in many other components. With XML configuration, you have to tell every component that uses that interface to use this one particular binding of that interface (or "bean" if you like). With annotation-based configuration, you just declare the binding once and everything else is taken care of automatically. This is very significant, and dramatically reduces the amount of configuration you have to write. It also means that when you add a new dependency to a component, you often don't have to change anything about your configuration at all!
That you have mock implementations of some interface is irrelevant. In unit tests you typically just create the mock and pass it in yourself... it's unrelated to configuration. If you set up a full system for integration tests with certain interfaces using mocks instead... that doesn't change anything. For the integration test run of the system, you're still only using 1 implementation and you only have to configure that once.
XML: You can inject anything anywhere
You can do this easily in Guice and I imagine you can in CDI too. So it's not like you're absolutely prevented from doing this by using an annotation-based configuration system. That said, I'd venture to say that the majority of injected classes in the majority of applications are classes that you can add an #Inject to yourself if it isn't already there. The existence of a lightweight standard Java library for annotations (JSR-330) makes it even easier for more libraries and frameworks to provide components with an #Inject annotated constructor in the future, too.
More than one implementation of an interface
Qualifiers are one solution to this, and in most cases should be just fine. However, in some cases you do want to do something where using a qualifier on a parameter in a particular injected class would not work... often because you want to have multiple instances of that class, each using a different interface implementation or instance. Guice solves this with something called PrivateModules. I don't know what CDI offers in this regard. But again, this is a case that is in the minority and it's not worth making the rest of your configuration suffer for it as long as you can handle it.
I have the following principle: configuration-related beans are defined with XML. Everything else - with annotations.
Why? Because you don't want to change configuration in classes. On the other hand, it's much simpler to write #Service and #Inject, in the class that you want to enable.
This does not interfere with testing in any way - annotations are only metadata that is parsed by the container. If you like, you can set different dependencies.
As for CDI - it has an extension for XML configuration, but you are right it uses mainly annotations. That's something I don't particularly like in it though.
In my opinion, this is more a matter of taste.
1) In our project (using Spring 3), we want the XML-configuration files to be just that: configuration. If it doesn't need to be configured (from end-user perspective) or some other issue doesn't force it to be done in xml, don't put the bean-definitions/wirings into the XML-configurations, use #Autowired and such.
2) With Spring, you can use #Qualifier to match a certain implementation of the interface, if multiple exist. Yes, this means you have to name the actual implementations, but I don't mind.
In our case, using XML for handling all the DI would bloat the XML-configuration files a lot, although it could be done in a separate xml-file (or files), so it's not that valid point ;). As I said, it's a matter of taste and I just think it's easier and more clean to handle the injections via annotations (you can see what services/repositories/whatever something uses just by looking at the class instead of going through the XML-file looking for the bean-declaration).
Edit: Here's an opinion about #Autowired vs. XML that I completely agree with: Spring #Autowired usage
I like to keep my code clear, as you pointed. XML feets better, at least for me, in the IOC principle.
The fundamental principle of Dependency Injection for configuration is that application objects should not be responsible for looking up the resources or collaborators they depend on. Instead, an IoC container should configure the objects, externalizing resource lookup from application code into the container. (J2EE Development without EJB - Rod Johnson - page 131)
Again, it just my point of view, no fundamentalism in there :)
EDIT: Some useful discussions out there:
http://forum.springsource.org/showthread.php?t=95126
http://www.theserverside.com/discussions/thread.tss?thread_id=61217
"But what is bad about xml?" It's yet another file to manage and yet another place to have to go look for a bug. If your annotations are right next to your code it's much easier to mange and debug.
Like all things, dependency injection should be used in moderation. Moreover, all trappings of the injections should be segregated from the application code and relegated to the code associated with main.
In general applications should have a boundary that separates the abstract application code from the concrete implementation details. All the source code dependencies that cross that boundary should point towards the application. I call the concrete side of that boundary, the main partition, because that's where 'main' (or it's equivalent) should live.
The main partition consists of factory implementations, strategy implementations, etc. And it is on this side of the boundary that the dependency injection framework should do it's work. Then those injected dependencies can be passed across the boundary into the application by normal means. (e.g. as arguments).
The number of injected dependencies should be relatively small. A dozen or less. In which case, the decision between XML or annotations is moot.
Also don't forget Spring JavaConfig.
In my case the developers writing the application are different that the ones configuring it (different departments, different technologies/languages) and the last group doesn't even has access to the source code (which is the case in many enterprise setups). That makes Guice unusable since I would have to expose source code rather than consuming the xmls configured by the developers implementing the app.
Overall I think it is important to recognize that providing the components and assembling/configuring an application are two different exercises and provide if needed this separation of concerns.
I just have a couple of things to add to what's already here.
To me, DI configuration is code. I would like to treat it as such, but the very nature of XML prevents this without extra tooling.
Spring JavaConfig is a major step forward in this regard, but it still has complications. Component scanning, auto-magic selection of interface implementations, and semantics around CGLIB interception of #Configuration annotated classes make it more complex than it needs to be. But it's still a step forward from XML.
The benefit of separating IoC metadata from application objects is overstated, especially with Spring. Perhaps if you confined yourself to the Spring IoC container only, this would be true. But Spring offers a wide application stack built on the IoC container (Security, Web MVC, etc). As soon as you leverage any of that, you're tied to the container anyway.
XML has the only benefit of a declarative style that is defined clearly separated from the application code itself. That stays independent from DI concerns. The downsides are verbosity, poor re-factoring robustness and a general runtime failure behaviour. There is just a general (XML) tool support with little benefit compared to IDE support for e.g. Java. Besides this XML comes with a performance overhead so it usually is slower than code solutions.
Annoations often said to be more intuitive and robust when re-factoring application code. Also they benefit from a better IDE guidance like guice provides. But they mix application code with DI concerns. An application gets dependent on a framework. Clear separation is almost impossible. Annotations are also limited when describing different injection behaviour at the same place (constructor, field) dependent on other circumstances (e.g. robot legs problem). Moreover they don't allow to treat external classes (library code) like your own source. Therefore they are considered to run faster than XML.
Both techniques have serious downsides. Therefore I recommend to use Silk DI. It is declarative defined in code (great IDE support) but 100% separated from your application code (no framework dependency). It allows to treat all code the same no matter if it is from your source or a external library. Problems like the robot legs problem are easy to solve with usual bindings. Furthermore it has good support to adapt it to your needs.

Is it worth wrapping a logging framework in an additional layer?

I'm currently looking at upgrading the logging mechanism in a medium-to-large-sized Java codebase. Messages are currently logged using static methods on a Debug class, and I have recommended switching from this to something like SLF4J or commons-logging.
The application architect prefers that I encapsulate the dependency on SLF4J (possibly by wrapping it up in the aforementioned Debug class). This will make it easier to change the logging implementation in the future.
This seems like overkill to me, as SLF4J is already abstracting the concrete logging implementation.
Is it worth wrapping a 3rd-party logging abstraction like SLF4J in another home-grown abstraction?
I entirely agree with you: wrappers of wrappers of wrappers are getting out of hand. I suspect that architect doesn't realize how SLF4J in particular can easily wrap any other logging system, so that "changing implementation" is perfectly feasible without yet another layer of wrappage.
I guess the motivation behind the architect's desire to wrap the wrapper (i.e. SLF4J), is to isolate your application from SLF4J. Clearly, invoking the SLF4J API from within your application creates a dependency on SLF4J. However, it is equally legitimate to want to apply the isolation principle repeatedly as discussed below. It reminds me of Richard Dawkins' question: If God created the universe, then who created God?
Indeed, you could also apply the isolation principle on the wrapper that wraps SLF4J. The cause of isolation would be ill served if the SLF4J-wrapper was somehow inferior to SLF4J. Although possible, it is rather rare for a wrapper to equal or surpass the original. SWT can be cited as a noteworthy counter-example. However, SWT is a sizable project with a significant cost. More to the point, an SLF4J-wrapper by definition depends on SLF4J. It is bound to have the same general API. If in the future a new and significantly different logging API comes along, code that uses the wrapper will be equally difficult to migrate to the new API as code that used SLF4J directly. Thus, the wrapper is not likely to future-proof your code, but to make it heavier by adding an additional indirection.
In short, even if you didn't have anything better to do, you shouldn't waste your time wrapping SLF4J because the added value of your wrapper is guaranteed to be near zero.
The topic is also broached in an SLF4J FAQ entry.
I would prefer to wrap it, but not for the stated reason. If the concern is the ability to swap out for another framework, use java.util.logging or SLF (java.util.logging isn't as easy to use as a wrapper, but it is quite doable), and swap away. The reason to use (yet another) wrapper is to codify in code the appropriate way of logging. Generally an application wants a subset, such as all system errors come with an exception, or have specific guidance about when to use the standard logging levels. Those decisions can be encapsulated in a few methods creating more consistent logging decisions over a large code base.
If, however, the motivation is just to make it possible to swap out implementations, don't reinvent the wheel. SLF is perfect for the job, just use it.
There is one exception to this. If your code is meant to be deployed into many possible app servers seemlessly, you do have to make sure that your logging choice doesn't risk conflicting with potentially older or newer versions of whatever the framework is using.
Explain to your Architecture Astronaut that slf4j already can act as a wrapper for other logging implementations, like log4j. So if you need to use some other logger in the future and there is no adapter for slf4j, you can write it when the need arises, but it will just be the adapter, instead of writing a whole logging framework that will just wrap some other logging framework and you need to design your framework for that and write your own adapter.
The problem with every wrapper is the decision of how you'll actually wrap and which functionality you'll provide:
commons.logging is providing a minimal set of logging functionality, hiding away additional functionality that the underlying framework might provide. You won't get advanced features like parameterized logging or the MDC.
SLF4J works the other way around. It handles advanced features like parameterized logging by implementing them on top of frameworks that aren't implementing them natively. This is the better way, IMHO.
I don't know your current Debug class but I guess it's pretty basic.
You probably won't have features like
the location of the logging message, i.e. name of the source file + line number
different logging levels
the ability to selectively set the level of different loggers, i.e. you don't have one logger per class, having the ability to set that logger to a certain level of interest, e.g. INFO, WARN. This is pretty crucial.
If your Debug class is pretty basic this is actually very nice for you :)
It means that you are likely able to switch over to SLF4J by performing a global search & destr... err... replace.
Make backups, though... ;)
See also Should new projects use logback instead of log4j?, What’s Up with Logging in Java?, Which log4j facade to choose?, Find a way in the java logging frameworks scene. and Do you find java.util.logging sufficient?. (Spoiler: You shouldn't use java.util.logging, pretty please)
If you're thinking of switching Logging frameworks in the future, it may be worthwhile to add an extra layer to where you can switch out the logger. Otherwise, if they provide everything that you will possibly need(using your crystal ball, of course) then it is probably ok to have a hard dependency on that framework.
If your current setup allows flexibility to change, you don't need a wrapper.

Categories

Resources