It's a Stragedy!No, it's not a typo. The title has a deliberate play on words that implies that incorrect strategies can end up in tragedy. While the word "tragedy" may be a bit strong, the thought process does have a ring of truth to it. In this chapter we attempt to give you helpful hints and tips to boost the performance of your code and your development team. We will break the discussion into logging strategies, development strategies, component strategies and testing strategies. Logging StrategiesLogging is a necessary function in any system. The problem arises when the logging is not implemented in an efficient manner. Before we get into the nuts and bolts of how to create an efficient logging implementation, we have to identify what logging efficiency is. In the spirit of the Separation of Concerns pattern, there are two problem domains to consider: log organization and log writing. Log organization is primarily concerned with how the log categories are organized, and how the log files are organized. Log writing has to do with the mechanics of writing log entries. Log writing is in turn split into at least two concerns, the output target and the formatting. Log OrganizationThe Avalon Framework and team advocate a category based approach to organizing loggers as opposed to a class name based approach. There is a very good reason for this. First is that categorization allows you to put information of like kind in one location. Second, it allows you to turn on and off an entire category of log messages. The arguments for the class name based logging usually fall under these assumptions:
While these arguments have their point, so does a strict category based logging approach:
The issue is made more complex by the fact that Log4J has a dot-notation hierarchical category system, but is most often used for the package/class hierarchy, and not by explicit names. Avalon Logging is an interesting approach, where the component declares the Loggers it want to have available in the Type descriptor, and the container satisfy this need, by mapping those categories to the underlying logging system's categories. Furthermore, you set the priority for each such category in the block.xml, which can be overridden in the config.xml. Log Category OrganizationWe argue that it is a mistake to use only one category for all logging. The reason is that you will inevitably need to turn on and off a whole class of messages. Another reason is that you will need at least one category for each log file you have. One effective approach is to separate your logging needs into roles and classifications. For instance, a network connection component may have logging roles of "connections", "traffic" and "client". If you have already decomposed your system into components, then you have one set of categories defined. I would use a shorthand name for the category names for simple reference (e.g. "resource" instead of "org.apache.avalon.excalibur.resource.ResourceManager"). The simplified names can be used for a broad set of classes. Using the same example, the name "resource" implies the Resource class, its manager, and anything that is directly associated with the concept of a "resource". You can also use classifications as a specialization of the role. Typically classifications are sub-categories. For instance, the full name of the "component" category would be "resource.component". This means that we are referring to the "component" classification for the "resource" role. Most of your logging needs can be organized into this two dimensional cross-section of Role and Classification. Roles are best for main categories due to their logical separation. Typical classifications are "component", "security", and "pool". These same classifications can be used as standard sub-categories of the different roles. This way your log entries can have fine-grained control that is logically organized. Log Writing
The mechanics of log writing can vastly affect the
performance of your code. For instance, if you concatenate several
strings together in your log messages, the Java Virtual Machine
converts the concatenation to a StringBuffer, and performs the
expensive
if( logger.isDebugEnabled() ) logger.debug( "Some debug message..." ); : : if( logger.isInfoEnabled() ) logger.info( "some complex info message" ); : : if( logger.isWarnEnabled() ) logger.warn( "WARNING! " ); : : if( logger.isErrorEnabled() ) logger.error( "We had some problems..." ); Finally, each logging system supports different types of log output destinations and formatting. It is important to study the performance impact on each of these features. For instance, Log4J can provide source file and line number of where the log message was called from, which is VERY expensive call, although very convenient in debugging environments, it must be taken out during production. Another example is to investigate the possible speed improvements of using asynchronous targets and buffered streams. It is not uncommon for many applications that unchecked logging result in negative speed impacts of a magnitude or more. Development StrategiesWork in progress. Component StrategiesWork in progress. Testing StrategiesWork in progress. |