Skip to content

antonsjava/jalw

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jalw

Jalw stands for just another logging wrapper. And this describes it's functionality. Instance of Jalw is lightweight wrapper over some 'real' system logging logger. This logger is used for real logging. Jalw do not provide any configuration. It provides only API.

Motivation

Many projects uses many different logging frameworks. Slf4j comes with idea how to unify this. But if you miss some trace logging functionality maybe Jalw helps you.

I like to log trace information about method name and method input params. It is possible to configure some logging systems to provide this information - but is it slow and it is not possible to use it in production environments.

Other way is to provide method name in each 'log' statement.

  log.debug("::methodName - this is real log message");

But it requires some extra effort and it makes copy/paste anti-pattern more complicated. When you copy part of the code - you must rename the method also in log statements.

Main features

Jalw helps you with following things.

  • Simplify adding method name information to each log statement. Method name should be provided only once.
  • Provides execution time to each log statement. It simplify finding slow methods.
  • Provides API for formating log messages independent from real logging API used. So you can use your ussual log formatting also in projects where you cannot use logging API you want.
  • Allows you (in limited way) to log messages, which was not logged before because log level was not allowed. It is usefull in case of some unexpected exceptions.
  • allows you to throws RuntimeException when some method input condition is reached.

Wrapping

Jalw requires some real logging API for logging. Like Slf4j or ... You can simply write your own wrapper over your logging API. Jalw brings JalwLogger interface, which abstracts the logging API. It requires two method for each log level

  • boolean isXXXEnabled() - which returns true if level XXX is opened for logging.
  • void XXX(String message) - which logs message to XXX level

It simplifies requiremets om logging API, but force Jalw to format logged messages to string form.

Jalw defines following levels of logging

  • trace
  • debug
  • info
  • warn
  • error
  • fatal

All this levels must be somehow mapped to real logging system using instance of JalwLogger and it is provided to Jalw for real logging.

The Jalw provides several implementations for other logging systems. You can use them directly or as example for your own implementation

All Implementations brings JalwLogger implementation and one factory method for creation Jalw instances.

Tracing

To trace method info it is necessary to provide method name to Jalw. You can log start of the method and of the method in following way

  Logger logger = Logger.getLogger(MyClass.class);
  ...
  private void aMethod(String text, int level) {
    Jalw jalw = SdkJalw.jalw(logger).start("aMethod", text, level);
    if(text == null) {
      jalw.end("The text param is empty");
      return;
    }
  ...
    jalw.end();
  }

It produces trace output like

  >- aMethod [The text param value] [1]  {aMethod - ms: 0}
  <- aMethod {aMethod - ms: 0}

or like

  >- aMethod [null] [1]  {aMethod - ms: 0}
  <- aMethod [The text param is empty] {aMethod - ms: 0}

So you can see start and end of the method execution in log file.

You can see text '{aMethod - ms: 0}' in each Jalw log statement automatically so it is not necessary to put method name there explicitly. You can find there also time from Jalw instance creation to execution of log statement. You can find slow methods by some log file searching.

Logging

For each level you can use several ways for logging. You can use which one you want Provided examples are for debug level, but it is same for all levels.

You can ask if logging is enabled

  if(jalw.debug()) {
  ...
  }  

You can log simple strings or any object toString().

  jalw.debug("simple string");
  jalw.debug(aVariable);

You can log stack trace of exception or limited stack trace

  jalw.debug(anException);
  jalw.debug(anException, 3);

You can log formated message using Slf4j format

  jalw.debug("parameter text: {}, parameter index: {}". text, index);

You can log formated message using printf format

  jalw.debugf("parameter text: %s, parameter index: %d". text, index);

You can log formated message using append like format

  jalw.toDebug().a("parameter text: ").a(text).a(" parameter index: ").a(index).log();

History

in some cases you want to log messages even they are actually not allowed to log out. For example you receive exception, you see it in log file because it is logged to error level, but you like to know input parameter of method, but it is logged to trace which was actually not allowed to log.

Jalw stores some limited buffer of messages and allows you to print them to other level when it was originally logged. Following example shows such usage.

  } catch (Exception e) {
     jalw.historyToError();
     jalw.error("Something strange happens").error(e);
  }

There is 50 message budffer enabled for each Jalw instance by default. You can change it in following way

      Jalw jalw = SdkJalw.jalw(logger).withoutHistory().start("aMethod"); // no history
      Jalw jalw = SdkJalw.jalw(logger).withHistory(100).start("aMethod"); // change limit

If message was not logged because it was not enabled the messages are formated in time of logging the history. So all abjects are printed in state as they are in history log time. So history can differ from state as if it was logged normally.

Thread context

In some cases you want to 'store' some traces of execution flow in thread. it is usefull when you have code with direct request processing. You can determine start of processing for context cleaning. And when you store some 'key' informations usefull for debugging application.

This information is then prointed in historyToError methods or you can process it by your own way.

For example you have some REST API interface where you obtain some id of modified object So you clean context store this information

  jalw.contextClean();
  jalw.context("REST update.{}", path);

In other method you can map path to tech {db} id of object to be modified

  jalw.context("DB content id: {}", object.getId());

Then in your exception handling code You van obtain previous information in you debug log.

  } catch (Exception e) {
     jalw.historyToError();
  }

Or you can priunt it by yourself.

  jalw.info("traces: {}", jalw.contextString());

Input condition check

If you like to check method input condition and throw an exception and you don;t mind that it is IllegalStateException. you can use something like

  jalw.checkEmpty(list).a("The input list is empty.").error(true);

This is replacement for

  if((list == null) || list.isEmpty()) {
    IllegalStateException e = new IllegalStateException("The input list is empty.");
    jalw.error(e.toString());
    jalw.error(e)
    jalw.end()
    throw e;
  }

Example

I hope it is clear what Jalw brings. So if you must use any log API you don't like and you are familiar with Jalw API I is necessary to write only one simple class and use it for instantiating Jalw.

This is example for Liferay logging API

import com.liferay.portal.kernel.log.Log;
import sk.antons.jalw.Jalw;
import sk.antons.jalw.JalwLogger;

public class LRJalw {
    public static Jalw jalw(Log logger) {
        return new Jalw(new LRJalwLogger(logger));
    }
    
    private static class LRJalwLogger implements JalwLogger {

        private Log logger = null;
        public LRJalwLogger(Log logger) {
            this.logger = logger;
        }         
        
        public boolean isTtraceEnabled() { return logger.isTraceEnabled(); }
        public boolean isDebugEnabled() { return logger.isDebugEnabled(); }
        public boolean isInfoEnabled() { return logger.isInfoEnabled(); }
        public boolean isWarnEnabled() { return logger.isWarnEnabled(); }
        public boolean isErrorEnabled() { return logger.isErrorEnabled(); }
        public boolean isFatalEnabled() { return logger.isErrorEnabled(); }

        public void trace(String msg) { logger.debug(msg); }
        public void debug(String msg) { logger.debug(msg); }
        public void info(String msg) { logger.info(msg); }
        public void warn(String msg) { logger.warn(msg); }
        public void error(String msg) { logger.error(msg); }
        public void fatal(String msg) { logger.error(msg); }

        
    }
}

Maven usage

   <dependency>
      <groupId>io.github.antonsjava</groupId>
      <artifactId>jalw</artifactId>
      <version>LASTVERSION</version>
   </dependency>

Jalw has implementation dependences to external libs. They are marked as provided so if you want to use Slf4j you must add dependency for Slf4j in your own project. To avoid eny version problems exclude all dependences.

   <dependency>
      <groupId>io.github.antonsjava</groupId>
      <artifactId>jalw</artifactId>
      <version>LASTVERSION</version>
      <exclusions>
        <exclusion>
          <groupId>*</groupId>
          <artifactId>*</artifactId>
        </exclusion>
      </exclusions>
   </dependency>

OSGI usage (Karaf)

   bundle:install mvn:com.github.antonsjava/jalw/1.1
   bundle:start com.github.antonsjava.jalw/1.1.0

Releases

No releases published

Packages

No packages published

Languages