CoralLog FAQ

Below some frequently asked questions about CoralLog.

  1. Does CoralLog use off-heap memory?
    No. CoralLog does not allocate any off-heap memory through sun.misc.Unsafe. You can log as many gigabytes as you want to your log files and CoralLog never produces any garbage for the GC. CoralLog does extensively use direct byte buffers which is off-heap memory allocated by the JVM in a more standard way.
  2. Does CoralLog use memory-mapped files?
    Memory-mapped files can be used for asynchronous logging since you write to memory and the OS is the one performing file I/O in the background, from memory to disk. CoralLog uses a different approach for asynchronous logging. It uses CoralQueue under the hood for blazing fast and garbage-free inter-thread communication. Therefore, instead of writing to a memory-mapped file, messages are written in nanoseconds to a high-performance queue that later passes them to a dedicated file I/O thread. CoralLog does support memory-mapped files for log files, but this option is off by default as it offers little gains for latency. It does help a bit for throughput and you can turn it on easily if throughput is important to you.
  3. Because CoralLog is asynchronous, don’t you lose messages in the queue in the event of a crash?
    No. CoralLog will automatically drain the queue using a shutdown hook in the event of a crash. You can also control the queue explicitly if you want with the methods below, but you don’t have to.

    // drain and close the the logger gracefully
    // this method will block, wait for the queue to be drained, wait for the logger to be closed and then return
     myLogger.drainCloseAndWait();
     
    // if you don't want to close, but just want to drain, you can do:
    // this method will block, wait for the queue to be drained and then return
    myLogger.drainAndWait();
    
    // drain and close the the logger gracefully
    // this method will NOT block, returning immediately, but all messages from this logger will
    // be processed before the logger is closed
    myLogger.close(); // returns immediately, but adds a close event in the queue for this logger
    
  4. Because CoralLog uses varargs, don’t you create garbage there?
    No. CoralLog implements its own varargs and supports up to 16 objects without creating any garbage.
  5. What about autoboxing? You will be creating garbage there, right?
    No. CoralLog offers a straightforward way to avoid autoboxing as the code below demonstrates.

    long id = 2342342342;
    
    // autoboxing will happen for id and garbage will be created
    myLogger.log("This is a log message!", "user=", "foo", "id=", id);
    
    // NO AUTOBOXING ANYMORE
    myLogger.log("This is a log message!", "user=", "foo", "id=", to_sb(id));
    
  6. Doesn’t CoralLog call toString() on objects creating garbage?
    No. For common objects, CoralLog knows how to log them without creating strings and garbage. That’s the case for: CharSequence, byte[], char[], ByteBuffer and Throwable. You can also add your own encoders for your objects so you can pass them by reference to a logger without having to worry about generating garbage through a toString() call.
  7. Can CoralLog be used in multithreaded environments?
    Yes. You can have multiple loggers being accessed by multiple threads as long as the same logger instance is not accessed concurrently by two different threads. If you want to access the same logger concurrently, then you can make the logger thread-safe. For level logging, the level loggers (Info, Warn, Debug, etc.) are already thread-safe by default. For event sourcing you can make a logger thread-safe when you create it through a LogConfig.

    LogConfig logConfig = new LogConfig(myDir, myFilename);
    
    // make the logger thread-safe
    logConfig.isSynchronized = true; // default is false
     
    Logger myLogger = Log.createLogger(logConfig);
    
    // feel free to share myLogger among threads now
    
  8. Is CoralLog compatible with SLF4J?
    Yes. CoralLog provides a wrapper for org.slf4j.Logger by extending the org.slf4j.helpers.MarkerIgnoringBase. To inject CoralLog in your application without any dependencies to CoralLog code or classes you just need to add the CoralLog jar in the front of your classpath (i.e. in front of any other SLF4J implementation). Below a simple SLF4J example that uses the CoralLog implementation under the hood. Note that there are no references to CoralLog in the code.

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class TestSlf4j {
    	
    	private final Logger logger = LoggerFactory.getLogger(TestSlf4j.class);
    	
    	public void logSomething() {
    		logger.info("This is a intergration test between CoralLog and Slf4j!");
    	}
    	
    	public static void main(String[] args) {
    		TestSlf4j test = new TestSlf4j();
    		test.logSomething();
    	}
    }
    
  9. Can I configure CoralLog through a properties file?
    Yes. CoralLog can scan the classpath (when -DcoralLogScanClasspath=true) for a file named CoralLogConfig.properties. If it finds it, it uses it. You can also use the command-line option -DcoralLogConfigFile to specify a different name/location for the config file. Note that the precedence for CoralLog configs is: file config > JVM command-line config > programmatically config. Below a simple properties file with some CoralLog configuration:

    # CoralLog configuration
    logFile = true
    logDir = /var/logs/myapps/
    logPattern = %p (%D/%M/%Y) - %T - %m%n
    
  10. What are the options for pattern defintion?
        D - day of the month (ex: 23)
        M - month of the year (ex: 02)
        Y - year (ex: 2015)
        T - time in the format HH:MM:SS.SSSSSS (microsecond precision)
        m - the message
        n - carriage return / new line
        p - the log level (INFO, DEBUG, WARN, etc)
        l - the class and line number where the log call was issued (if enabled)
        r - time in milliseconds since the application has started
        e - epoch in microseconds
        i - epoch in milliseconds
    

    So for example the pattern:

    ---> %p (%D/%M/%Y) - %T - %m%n

    would produce:

    logger.info("This is a test!"); // output below:
    // ---> INFO (05/10/2015) - 12:42:11.080161 - This is a test!"