<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Coral Blocks &#187; CoralLog</title>
	<atom:link href="https://www.coralblocks.com/index.php/category/corallog/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.coralblocks.com/index.php</link>
	<description>Building amazing software, one piece at a time.</description>
	<lastBuildDate>Sat, 25 Apr 2026 13:00:06 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.1</generator>
	<item>
		<title>Getting Started with CoralLog for Level Logging</title>
		<link>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-level-logging/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=getting-started-with-corallog-for-level-logging</link>
		<comments>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-level-logging/#comments</comments>
		<pubDate>Mon, 28 Jul 2014 16:21:48 +0000</pubDate>
		<dc:creator><![CDATA[cb]]></dc:creator>
				<category><![CDATA[CoralLog]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[async logging]]></category>
		<category><![CDATA[asynchronous]]></category>
		<category><![CDATA[asynchronous logging]]></category>
		<category><![CDATA[disruptor]]></category>
		<category><![CDATA[event sourcing]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[memory-mapped files]]></category>
		<category><![CDATA[throughput]]></category>

		<guid isPermaLink="false">http://www.coralblocks.com/index.php/?p=583</guid>
		<description><![CDATA[ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this article we present CoralLog, a powerful, ultra-low-latency and asynchronous logging library with a very intuitive and non-intrusive API. First we show you how you can use CoralLog for <em>level logging</em>, in other words, to log status messages from your application using the <em>log levels</em> available such as Debug, Trace, Error, etc. Then we show in a <a href="http://www.coralblocks.com/index.php/2014/07/getting-started-with-corallog-for-event-sourcing/" target="_blank">follow up article</a> how you can use CoralLog for <em>event sourcing</em>, in other words, to write any kind of message (i.e. data) to a file without adding latency or variance to the critical thread doing the logging.<span id="more-583"></span> If you are interested in the article with the performance numbers of CoralLog you can check <a href="http://www.coralblocks.com/index.php/2014/04/corallog-performance-numbers/" target="_blank">here</a>.</p>
<h2 class="coral">Level Logging</h2>
<p>Let&#8217;s start with a CoralLog Hello World:</p>
<pre class="brush: java; title: ; notranslate">
// this static import is all you need to start using CoralLog:
import static com.coralblocks.corallog.Log.*;

// then, anywhere in your code you can write:
Warn.log(&quot;Hello World!&quot;);
Info.log(&quot;Hello Again!&quot;);
</pre>
<p>When you execute the code above you see in the console:</p>
<pre>
13:54:21.322715-WARN Hello World!
13:54:21.322816-INFO Hello Again!
</pre>
<p>By default, CoralLog logs to the console (i.e. standard output) but you can easily change it to log to a file instead, as below:</p>
<pre class="brush: java; title: ; notranslate">
// anywhere in your code, you can write:
// (or pass -DlogFile=true in the JVM command-line)
Log.setFile(true);

// now everything goes by default to a file:
Error.log(&quot;Hello World!&quot;);
Info.log(&quot;Hello Again!&quot;);
</pre>
<p>Now if you look in your current directory, you will find a file named <em>corallog-levels.log</em> with the contents:</p>
<pre>
LOG OPENED - 16/05/2018 05:02:42.237
05:02:42.238762-ERROR Hello World!
05:02:42.238762-INFO Hello Again!
</pre>
<p>To change the name of the file, you can do:</p>
<pre class="brush: java; title: ; notranslate">
// (or pass -DlogLevelLoggerFilename=all-level-logging.log in the JVM command-line)
Log.setLevelLoggerFilename(&quot;all-level-logging.log&quot;);
</pre>
<p>To change the directory in where you want the log file, you can do:</p>
<pre class="brush: java; title: ; notranslate">
// anytime, anywhere in you code, you can write:
// (or pass -DlogDir=/Users/coralblocks/ in the JVM command-line)
Log.setDir(&quot;/Users/coralblocks/&quot;);
	
// now the log below goes to /Users/coralblocks/corallog-levels.log
Error.log(&quot;Hello World!&quot;);
</pre>
<p>Logging is easy and you can choose among the flavors below:</p>
<pre class="brush: java; title: ; notranslate">
// CoralLog varargs make it convenient to build your
// messages without the varargs array allocation overhead:
Warn.log(&quot;This is a log message!&quot;, &quot;user=&quot;, &quot;foo&quot;, &quot;age=&quot;, 21);
</pre>
<p>Outputs:</p>
<pre>
14:40:41.589516 This is a log message! user=foo age=21
</pre>
<p><b>NOTE:</b> With CoralLogs, you can use up to 16 objects in a varargs method call without producing any garbage, in other words, without causing the JVM to allocate a new object array to be passed to the method call.</p>
<p>When using varargs, the CoralLog default rule is to separate each object with a space character. The exception is when you have a string ending in &#8216;=&#8217;. Instead of &#8220;user= foo&#8221; it does not use the space and prints &#8220;user=foo&#8221;. If you don&#8217;t like this trick you can call the method below:</p>
<pre class="brush: java; title: ; notranslate">
// do not suppress the space in between object after an '=':
// default is true, to NOT have the space after an '=' sign
// (or pass -DlogNoSpaceAfterEqualSign=false in the JVM command-line)
Log.setNoSpaceAfterEqualSign(false);

// and you can also suppress the space completely with:
// default is false, to have the space between objects
// (or pass -DlogNoSpaceBetweenObjects=true in the JVM command-line)
Log.setNoSpaceBetweenObjects(true);
</pre>
<p>If you prefer, you can also use placeholders when constructing the log message, as below:</p>
<pre class="brush: java; title: ; notranslate">
Warn.log(&quot;This is a log message! user={} age={}&quot;, &quot;foo&quot;, 21);
</pre>
<p>Of course you can also take control of the whole message by preparing your own <code>StringBuilder</code>, <code>CharSequence</code>, <code>ByteBuffer</code> or <code>byte[]</code> and logging it as below:</p>
<pre class="brush: java; title: ; notranslate">
StringBuilder sb = new StringBuilder(1024); // cache and re-use this instance

sb.setLength(0);
sb.append(&quot;This is a log message!&quot;);
sb.append(&quot; user=&quot;).append(&quot;foo&quot;);
sb.append(&quot; age=&quot;).append(21);

Warn.log(sb);
</pre>
<h2 class="coral">Avoiding Autoboxing</h2>
<p><strong>One of the most important features of CoralLog is its zero garbage creation</strong>, in other words, you can log as much as you want without producing any (i.e. zero) garbage. The goal is to eliminate any GC overhead in the system. If you pass any primitive value (i.e. integer, long, boolean, etc.) to a log call, autoboxing will occur and garbage will be created under the hood by the JVM. CoralLog provides an easy way to escape autoboxing, as you can see below:</p>
<pre class="brush: java; title: ; notranslate">
// use the to_sb method to translate a primitive into a StringBuilder:
Warn.log(&quot;This is a log message!&quot;, &quot;user=&quot;, &quot;foo&quot;, &quot;age=&quot;, to_sb(21));
</pre>
<p>By using the method <code>to_sb</code>, you can translate <em>on-the-fly</em> a primitive value into a <code>StringBuilder</code> so no autoboxing occurs. You should know that whenever you write a primitive value to a <code>StringBuilder</code> no garbage is created, so another way to escape autoboxing is to write the whole message to a <code>StringBuilder</code> as the previous example showed:</p>
<pre class="brush: java; highlight: [6]; title: ; notranslate">
StringBuilder sb = new StringBuilder(1024); // cache and re-use this instance

sb.setLength(0);
sb.append(&quot;This is a log message!&quot;);
sb.append(&quot; user=&quot;).append(&quot;foo&quot;);
sb.append(&quot; age=&quot;).append(21); // no garbage is created when you write 21

Warn.log(sb);
</pre>
<p>The difference is that the <code>to_sb</code> method only writes the part of the message (i.e. the primitive values) that would cause autoboxing to a <code>StringBuilder</code>, instead of the whole message.</p>
<h2 class="coral">Log Levels and Colors</h2>
<p>When logging to the console (i.e. standard output), you can use colors to separate among the log levels. Linux/Unix terminals usually support this great feature, so to turn it on you can do:</p>
<pre class="brush: java; title: ; notranslate">
// call that anytime, anywhere in your code:
// (default is false because some terminals (win) do not support colors)
// (or pass -DlogColors=true in the JVM command-line)
Log.setColors(true);
</pre>
<p><a href="http://www.coralblocks.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-14-at-3.34.52-PM.png"><img src="http://www.coralblocks.com/wp-content/uploads/2014/07/Screen-Shot-2014-07-14-at-3.34.52-PM.png" alt="Screen Shot 2014-07-14 at 3.34.52 PM" width="1096" height="420" class="alignnone size-full wp-image-570" /></a></p>
<p>If you prefer, you can also change these colors with the code below:</p>
<pre class="brush: java; title: ; notranslate">
// change the Warn level to green:
// (or you can pass -DlogWarnColor=32 in the JVM command-line)
Warn.setColor(32);
</pre>
<p>The available colors are:</p>
<pre>
30 - Black
31 - Red
32 - Green
33 - Yellow
34 - Blue
35 - Purple
36 - Cyan
37 - White
</pre>
<h2 class="coral">Enabling/Disabling Log Levels</h2>
<p>CoralLog log levels, in order, are: Debug, Trace, Info, Event, Warn, Error, Alert, Critical and Emergency. To log everything on and above the Trace level, you can do:</p>
<pre class="brush: java; title: ; notranslate">
Trace.log(&quot;Can you see me?&quot;);

// log Trace and anything above Trace:
// (default is Info)
// (you can also pass -logLevel=trace in the JVM command-line)
Log.setLevel(Trace);

Trace.log(&quot;Now you can!&quot;);
</pre>
<p>In addition to setting the log level of the whole application, you can enable and disable individual logs, as the example below shows:</p>
<pre class="brush: java; title: ; notranslate">
Warn.enable(true); // no matter what the level is, it will be logged

Warn.enable(false); // not matter what the level is, it will NOT be logged

Warn.enable(null); // go by the current log level as usual...
</pre>
<p>Although the log method will not log anything if the level is not enabled, you can use the conditional below to avoid having to build a message and making the log call:</p>
<pre class="brush: java; title: ; notranslate">
if (Trace.isEnabled()) {
    Trace.log(&quot;Tracing something!&quot;);
}
</pre>
<p><!-- h2 class="coral">Asynchronous Logging</h2>
<p>By default, CoralLog is asynchronous, in other words, all file i/o is done in another thread so the overhead in the critical thread doing the logging is minimum. The log messages are transferred to the writing thread through a disruptor queue. If for some reason you want to turn off asynchronous mode, you can do:</p>
<pre class="brush: java; title: ; notranslate">
// turn off asynchronous mode
// (default is true)
// (or pass -DlogAsynchronous=false in the JVM command-line)
Log.setAsynchronous(false);
</pre>
<h2 class="coral">Closing the Asynchronous Thread</h2>
<p>The asynchronous thread (the writer thread doing the actual file i/o), is not a Java <em>daemon</em> thread, in other words, it will prevent the JVM from exiting unless this thread is properly terminated. That&#8217;s on purpose because we do not want this thread to be killed by the JVM on exit while it is still draining the queue. Therefore, if you want to graciously exit the JVM, you can use the method below:</p>
<pre class="brush: java; title: ; notranslate">
// block, drain the queue (all loggers), die and return...
AsyncThread.drainDieAndWait();
</pre>
<p>You can also drain all loggers and return like below:</p>
<pre class="brush: java; title: ; notranslate">
// block, drain the queue (all loggers) and return...
AsyncThread.drainAndWait();
</pre>
<p>There is also a non-blocking version that returns immediately:</p>
<pre class="brush: java; title: ; notranslate">
// returns immediately and signal the async thread to
// drain and die as soon as it can
AsyncThread.drainAndDie();
</pre>
<p><b>NOTE:</b> The cleanest way to exit the JVM is to close all your loggers and issue a <code>AsyncThread.drainDieAndWait()</code>.<br />
&#8211;><br />
<!-- h2 class="coral">Memory Mapped Files</h2>
<p>By default, CoraLog uses a <code>FileChannel</code> to log messages to disk. For maximum throughput you should use a memory-mapped file instead. The reason <code>FileChannel</code> is the default, and not memory-mapped files, is that for level logging you are usually not worried about throughput since you will probably not be logging millions of status messages per second.  Now latency is always important, and for that it does not matter if you are using a <code>FileChannel</code> or a memory-mapped file because CoralLog is asynchronous. </p>
<p>One disadvantage of memory-mapped files is that it can be hard to inspect or tail the file while logging is taking place. That’s because it is the OS that is making the decision of when to transfer data from memory to disk. Also a big chunk of memory (through a <code>MappedByteBuffer</code>) and file space (filled with blank spaces) must be pre-allocated. When the file fills up, in other words, when all the blank space has been overwritten with log data, the file is expanded with another pre-allocated chunk of the same size, so the file grows in chunks which <i>fools</i> the Linux tail command. Notice that CoralLog always truncates the file when rolling to a new chunk and when closing the logger, so no blank space is left in the file.</p>
<p>These disadvantages are very small when compared to the gains in throughput that memory-mapped files can deliver. For <em>level logging</em> you probably won&#8217;t care for throughput (just for latency), but for <a href="http://www.coralblocks.com/index.php/2014/07/getting-started-with-corallog-for-event-sourcing/" target="_blank">event sourcing</a> you surely will. That&#8217;s why for event sourcing, memory-mapped files are the default.</p>
<p>If you want, you can control memory-mapped files in CoralLog for level logging with the following code:</p>
<pre class="brush: java; title: ; notranslate">
// turn on memory-mapped files for level logging
// (default is false)
// (or pass -DlogMemoryMappedFile=true in the JVM command-line)
Log.setMemoryMappedFile(true);

// to change the memory-mapped buffer size (page size or chunk size as we talked above)
// (default is 50Mb)
// (or pass -DlogMemoryMappedBufferSize=100m)
Log.setMemoryMappedBufferSize(&quot;100m&quot;);
</pre>
<p>&#8211;></p>
<h2 class="coral">Additional Features</h2>
<p>CoralLog comes with many more features. Below we list some of them:</p>
<ul>
<li style="margin-bottom: 16px;">Encoders: so you don&#8217;t create any garbage with calls to <code>toString()</code>, in other words, the encoder will know how to write the object to a <code>ByteBuffer</code> without creating any garbage. CoralLog comes out-of-the-box with 5 encoders: one for <code>CharSequence</code> (<code>String</code>, <code>StringBuilder</code>, etc.), one for byte and char arrays, one for null objects, one for <code>ByteBuffer</code> and one for <code>Throwable</code>. These encoders are included by default and you can see them by calling Log.getEncoders(). You can also create and add your own encoders.
</li>
<li style="margin-bottom: 16px;">Interceptors: so you can intercept the <code>ByteBuffer</code> containing the log message and do whatever you want, such as send to syslog, write to a database or modify the message in any way you want before it makes it to the file (or console).
</li>
<li style="margin-bottom: 16px;">Debugging: you can also choose to print class names with line numbers in your log messages for debugging purposes. You can also choose to filter the log messages by package and class names so you can remove the noise and see only what you need when debugging.
</li>
<li style="margin-bottom: 16px;">Rolling a log file: at any time you can call the <code>roll()</code> method on any logger (Ex: <code>Warn.roll()</code>) to roll the log file. The current log file is renamed with the date in the filename and a fresh new one (i.e. WARN.log) is created.
</li>
<li>SLF4J: fully compatible with slf4j (http://www.slf4j.org)</li>
</ul>
<p><br/><br/></p>
]]></content:encoded>
			<wfw:commentRss>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-level-logging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Getting Started with CoralLog for Event Sourcing</title>
		<link>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-event-sourcing/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=getting-started-with-corallog-for-event-sourcing</link>
		<comments>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-event-sourcing/#comments</comments>
		<pubDate>Mon, 28 Jul 2014 16:27:42 +0000</pubDate>
		<dc:creator><![CDATA[cb]]></dc:creator>
				<category><![CDATA[CoralLog]]></category>
		<category><![CDATA[async logging]]></category>
		<category><![CDATA[asynchronous logging]]></category>
		<category><![CDATA[corallog]]></category>
		<category><![CDATA[event sourcing]]></category>
		<category><![CDATA[log4j]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[logging api]]></category>
		<category><![CDATA[logging library]]></category>

		<guid isPermaLink="false">http://www.coralblocks.com/index.php/?p=585</guid>
		<description><![CDATA[ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In a <a href="http://www.coralblocks.com/index.php/2014/07/getting-started-with-corallog-for-level-logging/" target="_blank">previous article</a> we talked about using CoralLog for <em>level logging</em>. In this article we will show you how to use CoralLog for <em>event sourcing</em>, in other words, how to open your own files and log any message or data you want with minimum latency, maximum throughput and zero garbage.<span id="more-585"></span> Keep in mind that once a <code>Logger</code> object is created, everything we discussed for level logging can be applied to event sourcing and vice-versa because the interface is exactly the same. So make sure you check <a href="http://www.coralblocks.com/index.php/2014/07/getting-started-with-corallog-for-level-logging/" target="_blank">our article on level logging</a> to get the full picture of the CoralLog features and the many ways to log.</p>
<h2 class="coral">Opening a file through a logger</h2>
<p>The basic method to create a <code>Logger</code> and start persisting your events and/or messages without complications is:<br />
<strong><font color="red">NOTE:</font></strong> The methods below create an <strong>asynchronous</strong> and <strong>non-synchronized</strong> logger by default. This is most probably what you want. The logger has a shutdown hook to drain and close the file so you don&#8217;t lose any information on exit. You don&#8217;t have to worry or do anything about that.</p>
<pre class="brush: java; title: ; notranslate">
// pass a filename to be created in the current directory
Logger myLogger = Log.createLogger(&quot;myLogFile.log&quot;);

// or you can pass the directory
Logger myLogger = Log.createLogger(&quot;/var/mydir/&quot;, &quot;myLogFile.log&quot;);
</pre>
<h2 class="coral">Using the LogConfig to create a logger</h2>
<p>You can also pass a <code>LogConfig</code> to the <code>createLogger</code> method to be able to create a logger using its various configuration options. For example, if you want to create a logger that does not print a carriage return on the end of each line you can do:</p>
<pre class="brush: java; highlight: [4]; title: ; notranslate">
LogConfig logConfig = new LogConfig(filename); // current directory
// or LogConfig logConfig = new LogConfig(dir, filename);

logConfig.includeLogEntrySeparator = false; // default is yes

Logger myLogger = Log.createLogger(logConfig);
</pre>
<p>Below all the <code>LogConfig</code> options with their defaults:</p>
<pre class="brush: java; title: ; notranslate">
	public final String filename;
	public String dir = Log.getDir();
	public boolean isSynchronized = false;
	public boolean isMemoryMapped = false;
	public String memoryMappedBufferSize = &quot;64m&quot;; // 64m
	public List&lt;Encoder&gt; encoders = Log.getEncoders();
	public boolean isAsynchronous = true;
	public boolean includeTopHeader = false;
	public boolean includeLogEntrySeparator = true;
	public String outputBufferSize = &quot;64k&quot;; // 64k (optimum)
	public boolean flushImmediately = false;
	public boolean includeTimestamp = true;
	public int secondsToFlush = -1;
	public String sizeToRoll = &quot;-1&quot;;
	public boolean isNoSpaceBetweenObjects = false;
</pre>
<h2 class="coral">Logging Events</h2>
<p>Below some examples on how you can log events with CoralLog:</p>
<pre class="brush: java; title: ; notranslate">
// log the contents of a byte[]
myLogger.log(byteArray);

// log the contents of a ByteBuffer
myLogger.log(byteBuffer);

// log the contents of a StringBuilder (or any CharSequence)
myLogger.log(stringBuilder);
</pre>
<p><b>NOTE:</b> None of the methods above generate any garbage.</p>
<p>You can also log more than one object using varargs, which CoralLog implements also without creating any garbage. Please refer to <a href="http://www.coralblocks.com/index.php/2014/07/getting-started-with-corallog-for-level-logging/" target="_blank">our article on level logging</a> for more details on the different approaches you can choose for logging. As we said in the beginning, the interface is the same so the same strategy applies for both event sourcing and level logging.</p>
<pre class="brush: java; title: ; notranslate">
myLogger.log(&quot;This is a log message!&quot;, &quot;user=&quot;, &quot;foo&quot;, &quot;age=&quot;, to_sb(21));

// or

myLogger.log(&quot;This is a log message! user={} age={}&quot;, &quot;foo&quot;, to_sb(21));

// or

StringBuilder sb = new StringBuilder(1024); // cache and re-use this instance
 
sb.setLength(0);
sb.append(&quot;This is a log message!&quot;);
sb.append(&quot; user=&quot;).append(&quot;foo&quot;);
sb.append(&quot; age=&quot;).append(21);
 
myLogger.log(sb);
</pre>
<p><br/><br />
<strong><font size="5" color="red">NOTE:</font></strong> The methods below are <strong>optional</strong> and are intended for the advanced user. <strong>You can safely ignore them</strong> because all our asynchronous loggers have a <strong>shutdown hook</strong> to drain the queue on exit. Also, if you can, you should pin the Async disk I/O thread to an isolated CPU core with the config:</p>
<pre>
-DlogProcToBindAsyncThread=CORE_ID
</pre>
<h2 class="coral">Draining and Closing an Asynchronous Logger</h2>
<p>When dealing with <em>asynchronous</em> logging, some care must be taken when closing a logger. CoralLog makes it straightforward to drain and close a logger so no data is ever lost due to the system exiting before the writer thread had a chance to drain the queue and log everything to disk. Below the details:</p>
<pre class="brush: java; title: ; notranslate">
// put a logger close event in the async queue
// this call returns immediately
myLogger.close();

// 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:
myLogger.drainAndWait();
// this method will block, wait for the queue to be drained,
// and return
</pre>
<p>You can use the methods above when you need to coordinate producer (the critical thread doing the logging) and consumer (the writer thread doing file i/o). Such coordination is usually needed when the system is terminating and you want to make sure there are no messages left in the ring-buffer queue.</p>
<h2 class="coral">Closing the Asynchronous Thread</h2>
<p>The asynchronous thread (the writer thread doing the actual file i/o), is not a Java <em>daemon</em> thread, in other words, it will prevent the JVM from exiting unless this thread is properly terminated. That&#8217;s on purpose because we do not want this thread to be killed by the JVM on exit while it is still draining the queue. Therefore, if you want to graciously exit the JVM, you can use the method below:</p>
<pre class="brush: java; title: ; notranslate">
// block, drain the queue (all loggers), die and return...
AsyncThread.drainDieAndWait();
</pre>
<p>You can also drain all loggers and return like below:</p>
<pre class="brush: java; title: ; notranslate">
// block, drain the queue (all loggers) and return...
AsyncThread.drainAndWait();
</pre>
<p>There is also a non-blocking version that returns immediately:</p>
<pre class="brush: java; title: ; notranslate">
// returns immediately and signal the async thread to
// drain and die as soon as it can
AsyncThread.drainAndDie();
</pre>
<p>The cleanest way to exit the JVM is to close all your loggers and issue a <code>AsyncThread.drainDieAndWait()</code>.</p>
<p><br/><br/></p>
]]></content:encoded>
			<wfw:commentRss>https://www.coralblocks.com/index.php/getting-started-with-corallog-for-event-sourcing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CoralLog Performance Numbers</title>
		<link>https://www.coralblocks.com/index.php/corallog-performance-numbers/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=corallog-performance-numbers</link>
		<comments>https://www.coralblocks.com/index.php/corallog-performance-numbers/#comments</comments>
		<pubDate>Fri, 18 Apr 2014 16:30:07 +0000</pubDate>
		<dc:creator><![CDATA[cb]]></dc:creator>
				<category><![CDATA[CoralLog]]></category>
		<category><![CDATA[corallog]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[throughput]]></category>

		<guid isPermaLink="false">http://coralblocks.soliveirajr.com/index.php/?p=129</guid>
		<description><![CDATA[ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this article we present the CoralLog performance numbers when logging messages to a file. <span id="more-129"></span></p>
<p>The machine used for the benchmarks below was an Intel i7 quad-core (4 x 3.50GHz) Ubuntu box overclocked to 4.50Ghz with a 120 GB solid-state drive.</p>
<p><strong>CoralLog is very fast!</strong> It performs asynchronous logging through a lock-free queue (i.e. CoralQueue) to be able to log a 256-byte message in <font color="blue"><strong>145 nanoseconds</strong></font> on average with a throughput around <font color="blue"><strong>2.7 million messages per second</strong></font>. And without producing any garbage.</p>
<h2 class="coral">Latency Numbers</h2>
<p>Because CoralLog is asynchronous, the latency in the producer side (i.e. in the thread doing the logging) is very small. For a latency benchmark, we measure the time it takes to log each message in isolation, in other words, without any contention in the asynchronous queue. This is accomplished by periodically calling the method <code>drainAndWait()</code> so we can be sure the queue is never full when we log a message. Below we compute the average time per message when we log two million messages, with an initial warmup of one million messages.</p>
<p>The command line to run the test is:</p>
<pre>
$ java -server -verbose:gc -cp target/corallog-all.jar -DlogSysErrOnQueueContention=true -DdeleteFile=true -DincludeTimestamp=true -DprocToBindProducer=2 -DlogProcToBindConsumer=3 -Xms2g -Xmx8g -XX:NewSize=512m -XX:MaxNewSize=1024m com.coralblocks.corallog.bench.Latency 256 1000000 3000000
</pre>
<p><b>Note:</b> You can check the source code of the latency test <a href="/index.php/corallog-latency-test/" target="_blank">here</a>.</p>
<p>The results are:</p>
<pre>
Messages: 3,000,000 (256 bytes in length)
Avg Time: <font color="blue">145.36 nanos</font>
Min Time: 94.0 nanos
Max Time: 13.995 micros
75% = [avg: 134.0 nanos, max: 157.0 nanos]
90% = [avg: 139.0 nanos, max: 171.0 nanos]
99% = [avg: 143.0 nanos, max: 214.0 nanos]
99.9% = [avg: 144.0 nanos, max: 652.0 nanos]
99.99% = [avg: 145.0 nanos, max: 1.117 micros]
99.999% = [avg: 145.0 nanos, max: 6.538 micros]
</pre>
<p><b>Note:</b> For latency is makes almost no difference if you include a timestamp before each log line. For throughput, as you will see below, it does.</p>
<h2 class="coral">Throughput Numbers</h2>
<p>For the throughput test, we log one million messages as fast as possible and compute the total time it takes to log them. Queue contention will occur so we should expect the average time per message (i.e. average latency) to be bigger than the numbers we found above. The message size is again 256 bytes and we perform 10 passes to have a better idea of the average numbers.</p>
<p><b>Note:</b> You can check the source code of the throughput test <a href="/index.php/corallog-throughput-test/" target="_blank">here</a>.</p>
<p><i><u>Without timestamps:</u></i></p>
<p>The command line to run the test is:</p>
<pre>
$ java -server -verbose:gc -cp target/corallog-all.jar -DincludeTimestamp=false -DdeleteFile=true -DprocToBindProducer=2 -DlogProcToBindConsumer=3 -Xms2g -Xmx4g -XX:NewSize=512m -XX:MaxNewSize=1024m com.coralblocks.corallog.bench.Throughput 1000000 10 256
</pre>
<p>The results are:</p>
<pre>
Batch 1 took 387.419 millis: Latency = 387 nanos per message | Throughput = 2,581,188 messages/sec
Batch 2 took 312.559 millis: Latency = 312 nanos per message | Throughput = 3,199,396 messages/sec
Batch 3 took 311.092 millis: Latency = 311 nanos per message | Throughput = <font color="blue">3,214,479 messages/sec</font>
Batch 4 took 462.953 millis: Latency = 462 nanos per message | Throughput = 2,160,048 messages/sec
Batch 5 took 358.261 millis: Latency = 358 nanos per message | Throughput = 2,791,258 messages/sec
Batch 6 took 395.448 millis: Latency = 395 nanos per message | Throughput = 2,528,780 messages/sec
Batch 7 took 354.197 millis: Latency = 354 nanos per message | Throughput = 2,823,287 messages/sec
Batch 8 took 340.067 millis: Latency = 340 nanos per message | Throughput = 2,940,593 messages/sec
Batch 9 took 389.391 millis: Latency = 389 nanos per message | Throughput = 2,568,114 messages/sec
Batch 10 took 351.775 millis: Latency = 351 nanos per message | Throughput = 2,842,724 messages/sec
</pre>
<p><i><u>With timestamps:</u></i></p>
<pre>
$ java -server -verbose:gc -cp target/corallog-all.jar -DincludeTimestamp=true -DdeleteFile=true -DprocToBindProducer=2 -DlogProcToBindConsumer=3 -Xms2g -Xmx4g -XX:NewSize=512m -XX:MaxNewSize=1024m com.coralblocks.corallog.bench.Throughput 1000000 10 256
</pre>
<p>The results are:</p>
<pre>
Batch 1 took 490.413 millis: Latency = 490 nanos per message | Throughput = 2,039,098 messages/sec
Batch 2 took 394.976 millis: Latency = 394 nanos per message | Throughput = 2,531,798 messages/sec
Batch 3 took 392.274 millis: Latency = 392 nanos per message | <font color="blue">Throughput = 2,549,238 messages/sec</font>
Batch 4 took 474.025 millis: Latency = 474 nanos per message | Throughput = 2,109,595 messages/sec
Batch 5 took 470.434 millis: Latency = 470 nanos per message | Throughput = 2,125,695 messages/sec
Batch 6 took 479.055 millis: Latency = 479 nanos per message | Throughput = 2,087,442 messages/sec
Batch 7 took 512.113 millis: Latency = 512 nanos per message | Throughput = 1,952,695 messages/sec
Batch 8 took 474.119 millis: Latency = 474 nanos per message | Throughput = 2,109,174 messages/sec
Batch 9 took 476.338 millis: Latency = 476 nanos per message | Throughput = 2,099,348 messages/sec
Batch 10 took 432.351 millis: Latency = 432 nanos per message | Throughput = 2,312,934 messages/sec
</pre>
]]></content:encoded>
			<wfw:commentRss>https://www.coralblocks.com/index.php/corallog-performance-numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CoralLog vs Log4J Performance Comparison</title>
		<link>https://www.coralblocks.com/index.php/corallog-vs-log4j-latency-comparison/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=corallog-vs-log4j-latency-comparison</link>
		<comments>https://www.coralblocks.com/index.php/corallog-vs-log4j-latency-comparison/#comments</comments>
		<pubDate>Thu, 12 Jun 2014 13:36:31 +0000</pubDate>
		<dc:creator><![CDATA[cb]]></dc:creator>
				<category><![CDATA[CoralLog]]></category>
		<category><![CDATA[asynchronous]]></category>
		<category><![CDATA[asynchronous logging]]></category>
		<category><![CDATA[corallog]]></category>
		<category><![CDATA[disruptor]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[log4j]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[percentiles]]></category>
		<category><![CDATA[ultra-low-latency]]></category>

		<guid isPermaLink="false">http://cb.soliveirajr.com/index.php/?p=384</guid>
		<description><![CDATA[ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this article we compare CoralLog and Log4J in terms of latency and throughput. Benchmarks were conducted against asynchronous Log4J 2.0-rc2 using Disruptor 3.2.1. <span id="more-384"></span></p>
<h2 class="coral">Latency</h2>
<p>As described in the article <a href="/index.php/2014/04/corallog-performance-numbers/" target="_blank">CoralLog Performance Numbers</a>, we measure the time it takes to log each message in isolation, in other words, without any contention in the asynchronous queue. But this time, because Log4J does not have a <code>drainAndWait</code> method, we use a pause after logging each message so we can be sure the message has time to leave the queue and make it to the file before we send the next message. Then we proceed to compute the average time for one-million messages, with an initial warmup of 500,000 messages.</p>
<p><b>Note1:</b> Thread-pinning was not used for both CoralLog and Log4J.</p>
<p><b>Note2:</b> Log4J pauses before each message are NOT a good idea. It does NOT guarantee the absence of queue contention, although it helps in that direction. A pause will always be a noise in a latency benchmark.</p>
<p><u>CoralLog results:</u></p>
<p>Command-line:</p>
<pre>
java -server -verbose:gc -cp target/corallog-all.jar -DuseTimestamper=true -DmsgSize=64 -DmemoryMappedFile=true -DmemoryMappedBufferSize=max -DdetailedBenchmarker=true -DprocToBindProducer=-1 -DlogProcToBindConsumer=-1 -DlogAsynchronousQueueCapacity=512 -Ddelay=10000 -Diterations=1000000 -DbeforeStart=100000 -DconsumerWaitStrategy=park-backoff -DproducerWaitStrategy=park-backoff -DdelayMethod=ASSIGNMENT -DdeleteFile=true -DblockCount=true -DexcludeNanoTimeCost=true -DwarmupTimes=5 -DwarmupMessages=100000 -Xms2g -Xmx4g -XX:NewSize=512m -XX:MaxNewSize=1024m com.coralblocks.corallog.bench.PerformanceTest3
</pre>
<pre>
Messages: 1,000,000 (64 bytes)
Avg Time: <font color="blue"><b>61.76 nanos</b></font>
Min Time: 32.0 nanos
Max Time: 11.517 micros
Garbage creation: <font color="blue">zero (no garbage is created)</font>
75% = [avg: 52.0 nanos, max: 65.0 nanos]
90% = [avg: 56.0 nanos, max: 90.0 nanos]
99% = [avg: 60.0 nanos, max: 122.0 nanos]
99.9% = [avg: 61.0 nanos, max: 322.0 nanos]
99.99% = <font color="blue">[avg: 61.0 nanos, max: 665.0 nanos]</font>
99.999% = [avg: 61.0 nanos, max: 3.449 micros]
</pre>
<p><u>Log4J results:</u></p>
<p>Command-line:</p>
<pre>
java -server -verbose:gc -cp target/corallog-all.jar:lib/log4j-1.2-api-2.0-rc2-SNAPSHOT.jar:lib/log4j-api-2.0-rc2-SNAPSHOT.jar:lib/log4j-core-2.0-rc2-SNAPSHOT.jar:lib/disruptor-3.2.1.jar -DuseTimestamper=true -DmemoryMappedFile=true -DmemoryMappedBufferSize=max -DdetailedBenchmarker=true -DprocToBindProducer=-1 -DlogProcToBindConsumer=-1 -DlogAsynchronousQueueCapacity=512 -Ddelay=10000 -Diterations=1000000 -DbeforeStart=100000 -DconsumerWaitStrategy=park-backoff -DproducerWaitStrategy=park-backoff -DdelayMethod=ASSIGNMENT -DdeleteFile=false -DmsgSize=64 -DblockCount=true -DexcludeNanoTimeCost=true -DwarmupTimes=5 -DwarmupMessages=100000 -DlogLibrary=LOG4J -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector -Dlog4j.configurationFile=lib/perf3PlainNoLocWithTimestamp.xml -Xms2g -Xmx4g -XX:NewSize=512m -XX:MaxNewSize=1024m com.coralblocks.corallog.bench.PerformanceTest3
</pre>
<pre>
Messages: 1,000,000 (64 bytes)
Avg Time: <font color="red"><b>890.44 nanos</b></font>
Min Time: 68.0 nanos
Max Time: 13.404 millis
Garbage creation: <font color="red">the more messages you write the more garbage is created</font>
75% = [avg: 682.0 nanos, max: 1.196 micros]
90% = [avg: 770.0 nanos, max: 1.243 micros]
99% = [avg: 818.0 nanos, max: 1.558 micros]
99.9% = [avg: 844.0 nanos, max: 11.402 micros]
99.99% = <font color="red">[avg: 854.0 nanos, max: 15.097 micros]</font>
99.999% = [avg: 857.0 nanos, max: 41.479 micros]
</pre>
<p><u>Log4J official numbers:</u><br />
<a href="http://www.coralblocks.com/wp-content/uploads/2014/06/l1.png"><img src="http://www.coralblocks.com/wp-content/uploads/2014/06/l1.png" alt="l1" width="1356" height="141" class="alignnone size-full wp-image-624" /></a></p>
<h2 class="coral">Throughput</h2>
<p><b>Note:</b> Thread-pinning was not used for both CoralLog and Log4J.</p>
<p><u>CoralLog results:</u></p>
<pre>
Time to send 1,000,000 messages with 64 bytes: 0.231396475 seconds
Avg time per message: 231.0 nanos
Messages per second: <font color="blue"><b>4,321,587</b></font>
Garbage creation: <font color="blue">zero (no garbage is created)</font>
</pre>
<p><u>Log4J results:</u></p>
<pre>
Time to send 1,000,000 messages with 64 bytes: 0.330282985 seconds
Avg time per message: 330.0 nanos
Messages per second: <font color="red"><b>3,027,707</b></font>
Garbage created for the GC: <font color="red">The more messages you write the more garbage is created</font>
</pre>
<p><u>Log4J official results:</u><br />
<a href="http://www.coralblocks.com/wp-content/uploads/2014/06/l2.png"><img src="http://www.coralblocks.com/wp-content/uploads/2014/06/l2.png" alt="l2" width="1361" height="103" class="alignnone size-full wp-image-625" /></a></p>
<h2 class="coral">Conclusion</h2>
<ul>
<li>CoralLog has an average latency 14 times lower than Log4J (61 nanos x 890 nanos)</li>
<li>CoralLog produces zero garbage. Log4J produces garbage in proportion to the number of messages written.</li>
<li>CoralLog has lower variance than Log4J, with a max latency of 11.517 micros against 13.404 millis from Log4J.</li>
<li>At the 99.99 percentile, CoralLog shows an average latency of 61 nanos with a max latency of 665 nanos. Log4J shows for the same percentile an average latency of 854 nanos with a max latency of 15 micros.</li>
<li>CoralLog has an average throughput 30% greater than Log4J (4,321,587 x 3,027,707) without producing any garbage while LOG4J produces a lot of garbage.</li>
</ul>
<p><br/><br/></p>
]]></content:encoded>
			<wfw:commentRss>https://www.coralblocks.com/index.php/corallog-vs-log4j-latency-comparison/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
