|
|||
|
On 2/25/2012 3:22 PM, Arne Vajhøj wrote:
> That looks as if you are almost building your own logging framework > on top of a logging framework. > > That does not make much sense to me. I can think of a use case for it though. Let's say you haven't decided which logging framework to use, or you want to be flexible as to which one to use. (Different customers of yours prefer different loggers.) (Not syntax checked or tested.) abstract class MyLogger { public static MyLogger getLogger( String name ) { MyLogger logger = Class.forName( System.getProperty("me.mystuff.MyLogger.logImpl", "me.mystuff.MyDefaultLogger" ).newInstance()); return logger; } public abstract void logStuff(Object...); } So the idea is that you wrap the logging framework in your own, and then you're free to provide an implementation that matches whatever logging framework you choose to use in the future. Maybe this is not for everyone, but I could see its advantages. Some folks might like java.util.Logger, some folks like log4j. And some might like things that I don't know about yet. A couple of other things. Lew wrote: public class Foo { final Logger logger = getLogger(getClass()); [...] } This requires that a logger is instantiated for each object as it is created. Potentially this is a lot of work, and each logger may not be used. (Even declaring the logger to be static still requires a logger per class loaded.) Whereas this: ... try { ... some stuff... } catch (Exception ex) { getLogger(getClass()).log( ... ); } creates the logger lazily and therefore doesn't spend any resources if logging happens to be never required. Lastly, I don't know about log4j, but I don't think the java.util.logging package uses threads when logging. Any IO operations the logger makes will block the calling thread. I've heard this is undesirable in most cases. So rolling your own framework also gives you control over threading issues too, which again might be important for some customers. |
|
|
||||
|
||||
|
|
|
|||
|
markspace wrote:
> Arne Vajhøj wrote: > >> That looks as if you are almost building your own logging framework >> on top of a logging framework. >> >> That does not make much sense to me. > > > I can think of a use case for it though. Let's say you haven't decided which > logging framework to use, or you want to be flexible as to which one to use. > (Different customers of yours prefer different loggers.) That's what Apache Commons logging is for. > (Not syntax checked or tested.) > > abstract class MyLogger { > > public static MyLogger getLogger( String name ) { > MyLogger logger = Class.forName( > System.getProperty("me.mystuff.MyLogger.logImpl", > "me.mystuff.MyDefaultLogger" ).newInstance()); > return logger; > } > > public abstract void logStuff(Object...); > } It's actually common for libraries to use either ju.logging or log4j without regard for your preference, with the result that both frameworks wind up in the same program. > So the idea is that you wrap the logging framework in your own, and then > you're free to provide an implementation that matches whatever logging > framework you choose to use in the future. Maybe this is not for everyone, but > I could see its advantages. Some folks might like java.util.Logger, some folks > like log4j. And some might like things that I don't know about yet. I think in Java those two pretty much have it sewn up. In any event, there's already > A couple of other things. > > Lew wrote: > > public class Foo > { > final Logger logger = getLogger(getClass()); > [...] > } > > This requires that a logger is instantiated for each object as it is created. No, it doesn't. It only creates one per class. > Potentially this is a lot of work, and each logger may not be used. (Even > declaring the logger to be static still requires a logger per class loaded.) That's not important overhead at all. It's a feature, not a bug. The logger being tied to the class (or its name) gives you class-level control over the logger behavior at deployment time by adjustment of the logging properties (or XML) configuration file. This is desirable. The logging object size pays for itself in spades with its functionality. > Whereas this: > > ... > try { > ... some stuff... > } catch (Exception ex) { > getLogger(getClass()).log( ... ); > } > > creates the logger lazily and therefore doesn't spend any resources if logging > happens to be never required. Lazy initialization is waaay overrated. First prove you have an optimization problem before you present an optimization solution. > Lastly, I don't know about log4j, but I don't think the java.util.logging > package uses threads when logging. Any IO operations the logger makes will > block the calling thread. I've heard this is undesirable in most cases. So Loggers are designed to be very fast unless used. So calls below the logging threshold add very, very little overhead. Calls above the threshold are usually warning or error logging, so the overhead there is masked by the exception mechanism and the fact that things are crashing. First prove you have an optimization problem before you present an optimization solution. > rolling your own framework also gives you control over threading issues too, > which again might be important for some customers. Unlikely, but remotely possible. That doesn't apply to the OP's situation, of course. But your analysis ignores the care that goes into those two logging frameworks to minimize the overhead of logging calls, and the substantial functionality that you either sacrifice or spend a fortune recreating in a roll-your-own. It also ignores the difficulty of beating their performance. You'd be hard-pressed to exceed the efficiency of these frameworks. Think long and hard before deciding to forego these two logging frameworks, then stick with them anyway. If you really, really, really, really, really, really need to spawn a thread to make logging faster, which you don't, you can do that over a regular ju.logging or log4j call. You don't have to throw out the baby with the bath water. -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedi.../c/cf/Friz.jpg |
|
|||
|
On 2/25/2012 10:20 PM, Lew wrote:
> markspace wrote: >> (Different customers of yours prefer different loggers.) > That's what Apache Commons logging is for. Back when I was playing with applets, I discovered by default that the jul logger creates a log file in your home directory. (There's a default logging.properties file created with every Java desktop installation and that's what it does). With unsigned applets, this means even trying to instantiate any part of the jul logging system will throw an exception, because the applet has no permissions for creating files. There might be ways around that, but it spooked me and I decided that since I didn't have direct control over a user's system, I couldn't rely on any defaults in the JRE installation. So I made a shell logging system that wrapped the jul logger and allowed me control, in case I had to use something besides jul entirely. BTW, I wasn't aware that Apache Commons logging was different than JULI/log4j. Thanks for pointing that out. >> >> This requires that a logger is instantiated for each object as it is >> created. > No, it doesn't. > > It only creates one per class. OK, assuming loggers are cached and reused, fair point. > Lazy initialization is waaay overrated. > > First prove you have an optimization problem before you present an > optimization solution. Well, that "optimization" is code that my IDE writes by default. It costs me nothing, so I'd rather prove that it's a problem before messing with it. > If you really, really, really, really, really, really need to spawn a > thread to make logging faster, which you don't, you can do that over a > regular ju.logging or log4j call. You don't have to throw out the baby > with the bath water. I've never had to spawn threads for logging, and the idea was something I've only seen presented once, so I'm not sure how useful the concept is. However, I keep it in mind as something that might have to happen someday. |
|
|||
|
On 02/26/2012 12:04 AM, markspace wrote:
> On 2/25/2012 10:20 PM, Lew wrote: > >> markspace wrote: >>> (Different customers of yours prefer different loggers.) > >> That's what Apache Commons logging is for. > > > Back when I was playing with applets, I discovered by default that the jul > logger creates a log file in your home directory. (There's a default > logging.properties file created with every Java desktop installation and > that's what it does). With unsigned applets, this means even trying to > instantiate any part of the jul logging system will throw an exception, > because the applet has no permissions for creating files. > > There might be ways around that, but it spooked me and I decided that since I > didn't have direct control over a user's system, I couldn't rely on any > defaults in the JRE installation. So I made a shell logging system that > wrapped the jul logger and allowed me control, in case I had to use something > besides jul entirely. > > BTW, I wasn't aware that Apache Commons logging was different than JULI/log4j. > Thanks for pointing that out. > > >>> >>> This requires that a logger is instantiated for each object as it is >>> created. > >> No, it doesn't. >> >> It only creates one per class. > > > OK, assuming loggers are cached and reused, fair point. It's not really a cache. The logger factory method is simply guaranteed to return the same instance of the same-identified logger, just as say 'Integer.valueOf(5)' is guaranteed to return the same 'Integer' instance each time within the program. <http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#getLogger(java.lang.String)> "Find or create a logger for a named subsystem. If a logger has already been created with the given name it is returned. Otherwise a new logger is created." <http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/Logger.html#getLogger(java.lang.String)> "Retrieve a logger named according to the value of the name parameter. If the named logger already exists, then the existing instance will be returned. Otherwise, a new instance is created." It's important to know what the system promises, and the Javadocs tell you. The logging frameworks are foundational and should be part of the early education of the Java programmer, along with the collections framework. Knowledge of things like that all same-named loggers point to the same logger instance is useful. >> Lazy initialization is waaay overrated. >> >> First prove you have an optimization problem before you present an >> optimization solution. > > > Well, that "optimization" is code that my IDE writes by default. It costs me > nothing, so I'd rather prove that it's a problem before messing with it. You mean the IDE generates lazy instantiation for you? It's a problem in that it is additional code that resists best-practice idioms without benefit. The fact that you have accepted someone else's default doesn't make it a great idea. Your lazy acceptance of a lazy initialization idiom is not good for the code, however much it may appear to you to save you the minute to change your IDE's default to a saner approach. I'm sensitive to habits, especially ones that lead to trouble. Maybe your classes by default aren't meant for concurrent programs, for example, but I never assume my classes won't be used that way. I also believe that if you practice safe idioms you don't accidentally forget to use one when you need it. Lazy instantiation has proven dangers and it causes things to be initialized in an unpredictable way and out of the normal class sequence for eagerly initialized items. Whether those dangers apply in this case or that case, it costs nothing to do things the safe way and not have to shift gears when you suspect danger. >> If you really, really, really, really, really, really need to spawn a >> thread to make logging faster, which you don't, you can do that over a >> regular ju.logging or log4j call. You don't have to throw out the baby >> with the bath water. > > > I've never had to spawn threads for logging, and the idea was something I've > only seen presented once, so I'm not sure how useful the concept is. However, > I keep it in mind as something that might have to happen someday. It was the idea you suggested, though. I was just responding with a way to follow your suggestion, with which I disagree BTW, that didn't involve having to reinvent the whole logging framework thing. -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedi.../c/cf/Friz.jpg |
|
|||
|
Lew wrote:
> markspace wrote: >> Lew wrote: >>> Lazy initialization is waaay overrated. >>> >>> First prove you have an optimization problem before you present an >>> optimization solution. >> >> Well, that "optimization" is code that my IDE writes by default. It costs me >> nothing, so I'd rather prove that it's a problem before messing with it. > > You mean the IDE generates lazy instantiation for you? It's a problem in that > it is additional code that resists best-practice idioms without benefit. The > fact that you have accepted someone else's default doesn't make it a great idea. > > Your lazy acceptance of a lazy initialization idiom is not good for the code, > however much it may appear to you to save you the minute to change your IDE's > default to a saner approach. > > I'm sensitive to habits, especially ones that lead to trouble. Maybe your > classes by default aren't meant for concurrent programs, for example, but I > never assume my classes won't be used that way. I also believe that if you > practice safe idioms you don't accidentally forget to use one when you need it. > > Lazy instantiation has proven dangers and it causes things to be initialized > in an unpredictable way and out of the normal class sequence for eagerly > initialized items. Whether those dangers apply in this case or that case, it > costs nothing to do things the safe way and not have to shift gears when you > suspect danger. That said, the logging frameworks themselves do lazy instantiation. Also, my comments here were meant to be very, very broad. Regular readers of my posts know that I usually point out that programming rules are not religions and there are times when they do or do not apply. For loggers, I instantiate according to scope needed, pure and simple, without regard for whether instantiation is lazy or eager. Since I use loggers heavily, typically with 'logger.debug("");' at the head of every method, it makes sense to have a 'private transient final Logger logger' class member most of the time. If I have a logger used only inside a particular block, it's instantiated inside that block the way you showed. This is in line with the best practice of minimizing variable scope. I don't just accept the IDE authors' default blindly, though. -- Lew Honi soit qui mal y pense. http://upload.wikimedia.org/wikipedi.../c/cf/Friz.jpg |
|
|||
|
On 12-02-26 02:20 AM, Lew wrote:
> markspace wrote: >> Arne Vajhøj wrote: >> >>> That looks as if you are almost building your own logging framework >>> on top of a logging framework. >>> >>> That does not make much sense to me. >> >> >> I can think of a use case for it though. Let's say you haven't decided >> which >> logging framework to use, or you want to be flexible as to which one >> to use. >> (Different customers of yours prefer different loggers.) > > That's what Apache Commons logging is for. As soon as a mention of commons logging comes up, I feel bound to mention SLF4J. :-) For the OP, if you're genuinely researching Java logging, check out SLF4J (http://www.slf4j.org/). This is a facade for other logging frameworks, so you'd actually implement using JUL or log4j or logback. Note that the same fellow who is responsible for log4j also drives slf4j and logback. Also while we are at it, I recommend http://www.javacodegeeks.com/2011/01...n-logging.html as a good list of tips for application logging. [ SNIP ] > It's actually common for libraries to use either ju.logging or log4j > without regard for your preference, with the result that both frameworks > wind up in the same program. Yes. There are a few different situations that arise here. In one case, the 3rd party library uses the *same* logging framework as you do. In which case, depending on overall environment and various classloaders, don't be surprised if your logging configuration also applies to that 3rd party library. You may start out with an unexpected spew of log statements in your log files until you finetune your loggers. From my standpoint I always see that extra flow of info with gratitude. I'll usually set first logging configuration to DEBUG for the packages in 3rd party libraries, just to see what I get. If the external parties also wrote good logging statements then the result is a major bonus, to again be filtered and directed as needed. In the other major case, the 3rd party library uses something different. Pay attention to that; hunt down its logging configuration file. You're not just using that library's Java API, you're also using its ability to log what's happening. Avoid having it be a black box that you can only debug into with decompiling to try to figure out what it's doing. >> So the idea is that you wrap the logging framework in your own, and then >> you're free to provide an implementation that matches whatever logging >> framework you choose to use in the future. Maybe this is not for >> everyone, but >> I could see its advantages. Some folks might like java.util.Logger, >> some folks >> like log4j. And some might like things that I don't know about yet. > > I think in Java those two pretty much have it sewn up. See above wrt slf4j and logback. [ SNIP ] AHS -- -- Gaiety is the most outstanding feature of the Soviet Union. Josef Stalin, November 1935 |
|
|||
|
Arne Vajhøj <arne@vajhoej.dk> wrote in
news:4f496fe1$0$281$14726298@news.sunsite.dk: > On 2/25/2012 6:29 PM, Novice wrote: >> Did you ever hear that old saying, attributed to various ancient >> personages? >> >> “He who knows not and knows not he knows not: he is a fool - shun >> him. He who knows not and knows he knows not: he is simple - teach >> him. He who knows and knows not he knows: he is asleep - wake him. He >> who knows and knows he knows: he is wise - follow him.” > > Wise words. > >> In that context, I consider myself "simple": I know that there are a >> bunch of things I don't know. I'm looking at the people in this >> newsgroup as being in the 'wise' category and am trying to learn from >> you. >> >> As I've said, I'm a one man Java shop in a town that doesn't seem to >> do much Java. I don't work in a professional Java shop so I have no >> professional Java code to look at or peers to learn from. So I'm >> floundering. That's why this newsgroup is important to me. I _AM_ >> trying to get better at this.... > > You may be able to download and look at some open source code that > uses logging. > Can you suggest any specific projects/products that you think are particularly well-written? I had thought of looking at such code before but I'm not sure I'd necessarily recognize well-written code if I found it. It might look strange to me but actually be brilliant or viceversa. If I start looking at code that is written by someone who knows less than I do, I'll go backwards, not forwards, in my learning. -- Novice |
|
|||
|
On 2/25/2012 11:22 PM, markspace wrote:
> On 2/25/2012 3:22 PM, Arne Vajhøj wrote: >> That looks as if you are almost building your own logging framework >> on top of a logging framework. >> >> That does not make much sense to me. > > I can think of a use case for it though. Let's say you haven't decided > which logging framework to use, or you want to be flexible as to which > one to use. (Different customers of yours prefer different loggers.) Commons Logging already exist to handle that! Arne |
|
|||
|
On 12-02-26 07:18 AM, Martin Gregorie wrote:
> On Sat, 25 Feb 2012 22:20:03 -0800, Lew wrote: > >> The logger being tied to the class (or its name) gives you class-level >> control over the logger behavior at deployment time by adjustment of the >> logging properties (or XML) configuration file. This is desirable. >> > That's an interesting approach, though not one that I use. I tend to > prefer a single logger per process with an associated level attribute, > and to sprinkle classes with logger calls specifying different levels so > I can vary the logged detail depending on what I need to see. The minimal > level may correspond to nothing more than reporting overall run > statistics. Next level will log method exits and show call arguments plus > return value. The level above that shows method entry and beyond that > anything that might be relevant in the method internals: both of these > are omitted unless the method is complex enough to require them. [ SNIP ] I don't see anything you say above as being in conflict with the "standard" use of individual loggers in Java logging frameworks. I can only speak for myself, but I hope that pretty much everyone does what I am about to describe, or at least gets it. When working through a given method in a given class, you decide that at various points you have information that should be logged. You also know for each piece of information what logging level applies: the association of an appropriate logging level (e.g. DEBUG, INFO, WARN, ERROR, or equivalents) with corresponding information to be logged is probably the most important decision that you, the log statement coder, can make. It's not going to change; it's not supposed to change. It is entirely appropriate to have two or three log statements one after another, each at a different level, each with different information. What a lot of developers do though is squash all that together into one log statement at one level: they have just defeated the purpose of logging. The point of having (typically) a logger per class, as Lew indicated, is to then give you the other piece of the puzzle - fine-grained configuration. This does exactly what you do with your "process" logger, and more: from that XML or .properties config file you can easily control which of your log statements in a given package or class get logged, by level. To summarize, the methods in class a.b.c.X get all "logged up", with statements at various carefully-chosen levels. From the config file we control for package a.b or a.b.c or even specifically for class a.b.c.X whether we want to see everything above INFO inclusive, say, or everything down to DEBUG. On a sidenote the configuration isn't just deployment time. With Java EE 5 and 6 servers it's generally reasonably straightforward to do a bit of coding to expose selected logging framework functionality through a JMX MBean, such as the ability to change levels by logger. I'll add that log4j does have a DOMConfigurator.configureAndWatch() method that can be used to load up XML configuration, and have a thread check for config file changes at intervals; I've seen this approach fail with app server restarts so I stick to JMX. AHS -- -- Gaiety is the most outstanding feature of the Soviet Union. Josef Stalin, November 1935 |
|
|||
|
On 2/25/2012 11:22 PM, markspace wrote:
> Lastly, I don't know about log4j, but I don't think the > java.util.logging package uses threads when logging. Any IO operations > the logger makes will block the calling thread. I've heard this is > undesirable in most cases. So rolling your own framework also gives you > control over threading issues too, which again might be important for > some customers. I don't think log4j write in a separate thread either. But I don't think it is necessary. If the call actually had to block until the data were written to the rotating plates, then it could be significant. But on modern OS'es the data will just be copied over to some system memory where it will be transferred to the RAID controller memory where it will be transferred to the memory in the drives before it eventually end up on the plates. Arne |
|
|||
|
On 2/26/2012 3:04 AM, markspace wrote:
> On 2/25/2012 10:20 PM, Lew wrote: >> markspace wrote: >>> (Different customers of yours prefer different loggers.) > >> That's what Apache Commons logging is for. > > Back when I was playing with applets, I discovered by default that the > jul logger creates a log file in your home directory. (There's a default > logging.properties file created with every Java desktop installation and > that's what it does). With unsigned applets, this means even trying to > instantiate any part of the jul logging system will throw an exception, > because the applet has no permissions for creating files. > > There might be ways around that, but it spooked me and I decided that > since I didn't have direct control over a user's system, I couldn't rely > on any defaults in the JRE installation. So I made a shell logging > system that wrapped the jul logger and allowed me control, in case I had > to use something besides jul entirely. I seem to recall that log4j is a bit more applet friendly than jul. Note that the applet should send log info back to the site it came from. Arne |
|
|||
|
On 2/26/2012 9:38 AM, Novice wrote:
> Arne Vajhøj<arne@vajhoej.dk> wrote in > news:4f496fe1$0$281$14726298@news.sunsite.dk: >> On 2/25/2012 6:29 PM, Novice wrote: >>> As I've said, I'm a one man Java shop in a town that doesn't seem to >>> do much Java. I don't work in a professional Java shop so I have no >>> professional Java code to look at or peers to learn from. So I'm >>> floundering. That's why this newsgroup is important to me. I _AM_ >>> trying to get better at this.... >> >> You may be able to download and look at some open source code that >> uses logging. > > Can you suggest any specific projects/products that you think are > particularly well-written? I had thought of looking at such code before > but I'm not sure I'd necessarily recognize well-written code if I found > it. It might look strange to me but actually be brilliant or viceversa. Most widely used open source Java server products would be fine. My immediate ideas would be products like Apache ActiveMQ and JBoss AS. Arne |
|
|||
|
On 2/26/2012 10:49 AM, Arne Vajhøj wrote:
> On 2/26/2012 9:38 AM, Novice wrote: >> Arne Vajhøj<arne@vajhoej.dk> wrote in >> news:4f496fe1$0$281$14726298@news.sunsite.dk: >>> On 2/25/2012 6:29 PM, Novice wrote: >>>> As I've said, I'm a one man Java shop in a town that doesn't seem to >>>> do much Java. I don't work in a professional Java shop so I have no >>>> professional Java code to look at or peers to learn from. So I'm >>>> floundering. That's why this newsgroup is important to me. I _AM_ >>>> trying to get better at this.... >>> >>> You may be able to download and look at some open source code that >>> uses logging. >> >> Can you suggest any specific projects/products that you think are >> particularly well-written? I had thought of looking at such code before >> but I'm not sure I'd necessarily recognize well-written code if I found >> it. It might look strange to me but actually be brilliant or viceversa. > > Most widely used open source Java server products would be fine. > > My immediate ideas would be products like Apache ActiveMQ and > JBoss AS. For something practically not used and of somewhat more questionable quality you could try: http://www.vajhoej.dk/arne/opensource/record/ Arne |
|
|||
|
Lew <noone@lewscanon.com> wrote in news:jibso4$bv2$1@news.albasani.net:
> Novice wrote: >> Lew wrote: >>> Novice wrote: >>>> Lew wrote: >>>>> Novice wrote: >>>>>> Lew wrote: >>>>>>> Logging is a great use case for aspects. However, there are >>>>>>> alternatives to lessening logging's overhead, too. You have to >>>>>>> weigh costs and benefits. >>>>>>> >>>>>> What are other good ways to do logging? >>>>> >>>>> log4j is my favorite. >>>>> >>>>>> Right now, the two main programs in my current project each >>>>>> create their own logger and then pass it to the classes they call >>>>>> in their parameters. >>>>> >>>>> I don't think that's a good pattern. Which logging library are you >>>>> using? >>>>> >>>> I'm using Java Logging. Does that answer your question or are you >>>> asking something else? >>>> >>>>> I have each class create its own logger (log4j style shown: >>>>> >>>>> package eegee; >>>>> import org.apache.log4j.Logger; >>>>> import static org.apache.log4j.Logger.getLogger; >>>>> public class Foo >>>>> { >>>>> final Logger logger = getLogger(getClass()); >>>>> >>>>> public void foo() >>>>> { >>>>> logger.debug(""); >>>>> // do the fooey stuff >>>>> try >>>>> { >>>>> // do the trying stuff >>>>> } >>>>> catch (FooException exc) >>>>> { >>>>> String msg = "trying stuff failed. "+ >>>>> exc.getLocalizedMessage(); logger.error(msg, exc); >>>>> throw new IllegalStateException(msg, exc); >>>>> } >>>>> } >>>>> } >>>>> >>>>> This boilerplate is what aspects aim to remove from the code and I >>>>> espouse retaining. >>>>> >>>> My code is not terribly different than that. >>> >>> Actually, what you do is different and some of that difference is >>> terrible. >>> >>> Why aren't you logging the exceptions? >>> >> Because this is the code that creates the logger. If it fails to >> create the logger, where would you like me to log the exception? > > Yeah, I figured that out after the fact. You were doing a weird thing > by creating a factory method to call the factory method to create the > logger. > >>> And what you are doing here is radically different from what I >>> proposed, hardly at all similar in any respect. I don't understand >>> why you think it's similar. >>> >> Okay, maybe it's completely different then. I thought it was the same >> spirit. > > No. The difference is that I put the logger code in each class, and > don't have a centralized factory factory. That's because the logging > framework already provides a factory and a way to configure it, so I > don't try to reinvent that entire mechanism. > >>>> Here's the actual code minus the Javadoc comment: >>>> >>>> ================================================== ============== >>>> public static Logger configureLogger(String className, String >>>> logFilePath, String logFileName, Locale locale, Formatter >>>> formatter, Level loggingLevel) { >>> >>> My goodness, don't use TABs! Especially not in Usenet posts! >>> >> Sorry. >> >>> This use of a separate logger factory that takes over what the >>> logging framework already does is, well, curious. >>> >>>> String METHOD_NAME = "configureLogger()"; //$NON-NLS-1$ >>> >>> You don't need this, and if you did it should be 'final' and named >>> according to the Java coding conventions. >>> >> I thought final was irrelevant in a method and only made a difference >> for instance variables? > > It's not irrelevant, depending on what you think is relevant. It > prevents reassignment of the reference, and as a comment lets > maintainers know the intent is to have an immutable reference. > > But you are correct that is actually wasn't so necessary here. > Relevant was probably not the right word to use there but it was the closest I could think of at the time. Some time ago, I saw a post where someone had a local variable defined as final and someone remarked that it wasn't necessary or appropriate or whatever to put final on a local variable. That's all I meant to say. I'm happy to put final on my local variables or leave it out, whichever is appropriate. >> You're right about the case of the name. That should be methodName >> for a method variable.... >> >>>> /* Ensure that the mandatory parameters have all been >>>> specified. */ if (className == null) { >>>> throw new IllegalArgumentException("The name of the >>>> class must >>>> be provided."); //$NON-NLS-1$ >>> >>> You didn't log this! >>> >> Where would you like me to log this? > > 'logger.severe()' right at the point, just before the throw. > >>> And those "$NON-NLS-1$" comments are highly distracting. >>> >> Sorry, I should have stripped them and the tabs out of the code >> first. > > Actually, you should indent with spaces not TABs routinely. Fair enough. I've gone into Eclipse, nosed around until I found where the tabs are created (in "Formatter") and created a new profile that uses spaces instead of tabs. > And strip > out the superfluous comments in your own code, too - that is, if > they're actually superfluous. > When I write code, I typically write a comment first to express the intent of what I want the next line or lines to do. Then I write the code and leave the comment there due to the brainwashing I got in my early days about always commenting everything. I try very hard to choose very clear names for things like variables, methods, and classes and I'd like to think the code is nearly self-explanatory most of the time without the need for comments. I'm sometimes tempted to erase all or most of the comments but then it occurs to me that what is obvious to me may not be so obvious to a total beginner and maybe it's a good thing to leave the comments there for their sake. In short, I agree that the comments in the method I posted don't really need to be there for my sake but, as long as I keep them accurate - and I usually do - they might conceivably help someone else. >>>> } >>>> >>>> if (logFilePath == null) { >>>> throw new IllegalArgumentException("The log file path >>>> must be >>>> provided."); //$NON-NLS-1$ >>>> } >>>> >>>> if (logFileName == null) { >>>> throw new IllegalArgumentException("The log file name >>>> must be >>>> provided."); //$NON-NLS-1$ >>>> } >>>> >>>> if (locale == null) { >>>> throw new IllegalArgumentException("The locale must be >>>> provided."); //$NON-NLS-1$ >>>> } >>>> >>>> >>>> /* Create the logger. */ >>>> Logger logger = Logger.getLogger(className); >>>> >>>> /* Create path identified by logFilePath if it does not >>>> exist. */ File path = new File(logFilePath); >>> >>> Really? >>> >>> I can't go on. It's too painful. >>> >> Why? Telling me it's awful without saying why doesn't teach me >> anything. > > I didn't stop there. I did say why. > I hadn't got that far yet ;-) >>>> I put that in a utility class in my Common project. Then any >>>> program that wants a logger just executes this one method passing >>>> the appropriate parameters. > > You don't need that. You just call 'Logger.getLogger()'. The utility > class is a whole lot of weird complication that you don't need. > >>> But, splutter, but, ... that's what the existing >>> 'Logger.getLogger()' method does! >>> >>> You're doing everything by hand that the framework does for you! >>> >> So I just execute Logger.getLogger() and a logger will be magically >> created that is exactly where I want it to be with exactly the file >> name I want to ensure that it is in the right format, XML in my case >> and with exactly the right logging level and handlers? I thought I >> had to do SOME of the work to ensure I got what I wanted. > > Yes, that is correct. > I gave your suggestion a try in my sandbox, where I'm playing with Aspects. I wrote this little class: ================================================== ======= package test; import java.util.logging.Level; import java.util.logging.Logger; public class TestLogging { public static void main(String[] args) { @SuppressWarnings("unused") TestLogging test = new TestLogging(); } public TestLogging() { Logger logger = Logger.getLogger("test"); logger.logp(Level.INFO, "myClass", "myMethod", "Monday"); logger.logp(Level.INFO, "myClass", "myMethod", "Tuesday"); logger.logp(Level.INFO, "myClass", "myMethod", "Wednesday"); logger.logp(Level.INFO, "myClass", "myMethod", "Thursday"); logger.logp(Level.INFO, "myClass", "myMethod", "Friday"); logger.logp(Level.INFO, "myClass", "myMethod", "Saturday"); logger.logp(Level.INFO, "myClass", "myMethod", "Sunday"); } } ================================================== ============ The code ran fine and the logging statements all appear nicely in red on my console. So far, so good. But I'd like them to appear in a log file somewhere, too. My logging.properties has the following lines: handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler java.util.logging.FileHandler.pattern = %h/java%u.log java.util.logging.FileHandler.limit = 50000 java.util.logging.FileHandler.count = 1 java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter By my reckoning, that should ensure that I'm also getting a log file and, since I'm running on Windows XP, I should be able to find it at C: \Documents and Settings\[Windows ID]\javaX.log. Well, I've got a java0.log through java4.log in that directory but none of them contain my logging statements. The only other place I can find to look, suggested by this site - http://docs.oracle.com/javase/1.5.0/...nt/deployment- guide/tracing_logging.html - translates to C:\Documents and Settings \[Windows ID]\Application Data\Sun\Java\Deployment\log. There's exactly one file in that directory and it is a Java log with the ungainly name of plugin5581819941091650582.log but it contains only this: <?xml version="1.0" encoding="windows-1252" standalone="no"?> <!DOCTYPE log SYSTEM "logger.dtd"> <log> </log> I'm not sure where else to look so I'm going back to the docs to see what other clues I can find. I suspect that the indirection involved in trying to find the log files was another factor in which I decided to create the loggers the way I did.... The logged files simply aren't much use if you can't find them. >>>> I realize that I could have each class create its own logger and >>>> log but >>> >>> Huh? >>> >>> No! >>> >>>> would seem to guarantee a proliferation of logs that would be a >>>> pain to find. It seems reasonable to me that if I have a bunch of >>>> programs, >>> >>> No, no, no, no. >>> >>> You don't create multiple log files, one per class. Where did you >>> get that notion? >>> >> Huh? You seem to be contradicting yourself. Are you saying I should >> create one logging file per class or not? And why have a separate >> logging > > No. I never said nor implied that you should have one logging file per > class. That one's on you, brother. > Okay. Your phrasing was a bit confusing. I read it as "You don't create multiple files, (you create) one per class." Apparently that's not what you mean after all. Sorry. >> file for each class? Isn't it more logical to have all the messages >> that come from one program, say Foo, appear in the same log? Isn't >> the poor > > Yes, but why are you arguing a point not in dispute? > Because your phrasing seemed to imply that I DID want one log per class. >> Sysop going to be excessively busy if he has to check a separate log >> for each and every one of the - hundreds? thousands? - of classes in >> the system? Wouldn't it be more logical to group logs on the basis of >> which application is invoking the class? Therefore, if method >> getCurrentWeekdayName had problems while executing program Foo, the >> Foo log would contain the information? Wouldn't the person running >> Foo be the one that's notifying the SysOp that something screwy just >> happened while running Foo? Then the name of the application would be >> a huge head start in finding the problem: just look in the Foo log >> and all will be revealed. Or at least enough to get started. > > How you do go on. > > No one is suggesting anything like that scenario. so cool your jets, > Cadet! > > Wow. > Sorry. I was confused by what you seemed to imply. >>> You set up the logging in the configuration file. Done. Simple. >>> >> What configuration file? I'm not sure what you mean. First, I'm not >> sure what you mean by a configuration file. Second, are you saying >> that all applications will normally have a configuration file? I >> don't remember coming across those in the Java Tutorial, for example, >> or even seeing them mentioned in this newsgroup. > > A configuration file is a file that contains configuration > information. > I'd guessed that much ;-) I'm trying to figure out what they contain, where I put them, etc. Reading ahead, you're about to explain that.... > As far as what you don't remember, if you follow the link from the API > docs for java.util.logging: > <http://docs.oracle.com/javase/7/docs...ng/package-sum > mary.html> > > You come across a recommendation to read the introduction to Java > logging, which I sure hope you followed: > "Related Documentation > For an overview of control flow, please refer to the Java Logging > Overview." which links you to > <http://docs.oracle.com/javase/7/docs...gging/overview > .html> wherein you would have read, had you read it, > <http://docs.oracle.com/javase/7/docs...gging/overview > .html#a1.15> "The APIs are structured so that an initial set of > configuration information is read as properties from a configuration > file." > > As for the tutorials, you have > <http://lmgtfy.com/?q=Java+logging+tutorial> > which among other links will find you > <http://forward.com.au/javaProgramming/javaGuiTips/javaLogging.html> > that covers a little about the "logging.properties" file. > Actually, I have been in all of those documents in the last several hours as I've been trying to puzzle out the right way to do logging. I'd seen all of them before at some point, but it was a fair while ago. Back then, I played with logging and came up with the logging code I posted (more or less). I truly don't remember how I got to that code though. At a guess, I didn't want the logs to go where the logging properties file wanted to put it and wanted it in a directory within each project so that it was more convenient, rather than putting all logs in the same directory. As for the term "configuration file" I didn't realize you meant "logging.properties". That was my confusion there; I don't recall hearing that called a configuration file before and thought you were talking about something completely new and outside my experience. >> If this is some routine thing that professional developers do, great. >> I obviously need to know about it. Can you point me to a tutorial or >> whatever that will explain what they are and how to create them? > > GIYF, dude. > GIYF?? >>> You are re-inventing the logging wheel. You said, >>>> Goodness no! I am using the Java Logging classes to do my logging. >>>> Sorry if that wasn't clear. >>> >>> but you aren't using it correctly. What you are doing is defeating >>> the built-in features and reinventing everything. Don't do that. >>> >> That was not my intention. I'm off to look at the logging classes >> again and see how I can avoid reinventing the wheel. I'm really not >> seeing why you say that yet. I'm using the standard Java Logging >> classes. I've > > Abusing > not deliberately, I assure you. >> tweaked the properties file that governs logging a little bit to get >> the > > Huh. That's the configuration file, dude. > Now the penny drops.... >> effect that I wanted and I created my own variant on the XMLFormatter >> that is only very slightly different. Aside from that, I'm using the >> vanilla logging classes. I'm not sure how that constitutes >> reinventing the framework. But, as I said, I'm going to review the >> logging classes now and see if I'm overcomplicating the creation of >> the logger as you say. Perhaps I am.... > > The properties file specifies the log file, the log level (by type if > you so choose), the output format, whether you report the class and > method being logged - all the things you did manually in your utility > class. > >>> And when I said you should know both ju.logging and log4j, somehow >>> you inferred that to mean that you should use both in the same >>> program. Such leaps you make! Settle back and stick with inferences >>> that actually follow from what I say. >>> >> Well, here's the exact quote: >> >> "Use log4j or java.util.logging (OR BOTH)". [emphasis added] > > Not in the same code! Yeesh. > > ... >> As I've said, I'm a one man Java shop in a town that doesn't seem to >> do much Java. I don't work in a professional Java shop so I have no >> professional Java code to look at or peers to learn from. So I'm >> floundering. That's why this newsgroup is important to me. I _AM_ >> trying to get better at this.... > > Of course, hence the detailed feedback. > Which I appreciate, even if I seem a bit grumpy or frustrated at times. But I'm still confused about the scope of my logs. According to the logging overview, I want the argument to Logger.getLogger() to be "A name for the logger. This should be a dot-separated name and should normally be based on the package name or class name of the subsystem, such as java.net or javax.swing." I expect that they are assuming that each project has a unique package name. Therefore, if my company is novice.com, then the Foo project will presumably have a package named com.novice.foo and the Bar project will have a package named com.novice.bar. Then, the logging for the Foo project will be based on Logger.getLogger("com.novice.foo"), right? Then every class within the Foo project will have the line: Logger logger = Logger.getLogger("com.novice.foo"); Have I got this so far? If so, the next logical step would be to treat all the stuff in the Common project similarly. If I put all of those classes in package com.novice.common, then each class would have this: Logger logger = Logger.getLogger("com.novice.common"); Or would it be better to get a reference to the logger within Foo and pass that to the classes in the Common project so that they write to the logger used by the instantiating class from Foo? Now, as it turns out, I've actually got a bunch of packages in project Common. I'm separating different kinds of common classes via packages. I'm not sure now if that is a good idea or a bad one. I've got separate packages with the Common project for utilities, for classes dealing with preference handling, for classes that are just simple lookups (including Enums), classes that create generic panels for GUIs, etc. So maybe I need to ask first if it is a bad idea to separate my common code into categories or if it is better to lump it all together into a single package. If keeping the separate packages is a good idea, then I need a bit of guidance on whether there should be a separate logger for each package or whether I'm better to write all messages from all Common classes to the same logger, e.g. com.novice.common despite their different packages. Now, if Project Foo only uses code from one other project, Common, I only have two logs to worry about, the one that has all the Foo stuff and the one that has all the Common stuff. That's not too bad. Then again, maybe it would be better to use Logger.getLogger("com.novice") and write every message from every class I write to the very same log, regardless of project. What is the best practice here? I feel like I'm starting to see what you have in mind but I hope you stay with me for just a bit longer until we've hashed the last bits out. I don't want to go off in the wrong direction again so I need your confirmation that I'm starting to get it now. -- Novice |
|
|||
|
On 2/26/2012 12:22 PM, Novice wrote:
> But I'm still confused about the scope of my logs. According to the > logging overview, I want the argument to Logger.getLogger() to be "A name > for the logger. This should be a dot-separated name and should normally > be based on the package name or class name of the subsystem, such as > java.net or javax.swing." > > I expect that they are assuming that each project has a unique package > name. Therefore, if my company is novice.com, then the Foo project will > presumably have a package named com.novice.foo and the Bar project will > have a package named com.novice.bar. Then, the logging for the Foo > project will be based on Logger.getLogger("com.novice.foo"), right? Then > every class within the Foo project will have the line: > > Logger logger = Logger.getLogger("com.novice.foo"); > > Have I got this so far? > > If so, the next logical step would be to treat all the stuff in the > Common project similarly. If I put all of those classes in package > com.novice.common, then each class would have this: > > Logger logger = Logger.getLogger("com.novice.common"); > > Or would it be better to get a reference to the logger within Foo and > pass that to the classes in the Common project so that they write to the > logger used by the instantiating class from Foo? The standard is to use the full (with package) class name as the name of the logger. Because logger configuration is applied tree wise, then you can still configure at package level. If you used package name as logger name, then you could not configure by class. Arne |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|