<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sematext</title>
    <description>The latest articles on DEV Community by Sematext (@sematext).</description>
    <link>https://dev.to/sematext</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F551%2Ffd29451f-4d87-4cda-88d3-81be40dc6ad2.jpg</url>
      <title>DEV Community: Sematext</title>
      <link>https://dev.to/sematext</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sematext"/>
    <language>en</language>
    <item>
      <title>Java Logging Best Practices: 10+ Tips You Should Know to Get the Most Out of Your Logs</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Thu, 10 Sep 2020 17:40:07 +0000</pubDate>
      <link>https://dev.to/sematext/java-logging-best-practices-10-tips-you-should-know-to-get-the-most-out-of-your-logs-593c</link>
      <guid>https://dev.to/sematext/java-logging-best-practices-10-tips-you-should-know-to-get-the-most-out-of-your-logs-593c</guid>
      <description>&lt;p&gt;Having visibility into your Java application is crucial for understanding how it works right now, how it worked some time in the past and increasing your understanding of how it might work in the future. More often than not, &lt;a href="https://sematext.com/blog/log-analysis/" rel="noopener noreferrer"&gt;analyzing logs&lt;/a&gt; is the fastest way to detect what went wrong, thus making logging in Java critical to ensuring the performance and health of your app, as well as minimizing and reducing any downtime. Having a &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;centralized logging and monitoring solution&lt;/a&gt; helps reduce the Mean Time To Repair by improving the effectiveness of your Ops or &lt;a href="https://sematext.com/blog/devops-roles/" rel="noopener noreferrer"&gt;DevOps team&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By following &lt;a href="https://sematext.com/blog/best-practices-for-efficient-log-management-and-monitoring/" rel="noopener noreferrer"&gt;logging best practices&lt;/a&gt; you will get more value out of your logs and make it easier to use them. You will be able to more easily pinpoint the root cause of errors and poor performance and solve problems before they impact end-users. So today, let me share some of the &lt;strong&gt;best practices you should follow when working with Java applications&lt;/strong&gt;. Let’s dig in.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Use a Standard Logging Library
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://sematext.com/blog/java-logging/" rel="noopener noreferrer"&gt;Logging in Java&lt;/a&gt; can be done a few different ways. You can use a dedicated logging library, a common API, or even just write logs to file or directly to a dedicated logging system. However, when choosing the logging library for your system think ahead. Things to consider and evaluate are performance, flexibility, appenders for new &lt;a href="https://sematext.com/blog/best-log-management-tools/" rel="noopener noreferrer"&gt;log centralization solutions&lt;/a&gt;, and so on. If you tie yourself directly to a single framework the switch to a newer library can take a substantial amount of work and time. Keep that in mind and go for the API that will give you the flexibility to swap logging libraries in the future. Just like with the switch from Log4j to &lt;a href="http://logback.qos.ch/" rel="noopener noreferrer"&gt;Logback&lt;/a&gt; and to &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4j 2&lt;/a&gt;, when using the &lt;a href="http://www.slf4j.org/" rel="noopener noreferrer"&gt;SLF4J&lt;/a&gt; API the only thing you need to do is change the dependency, not the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Select Your Appenders Wisely
&lt;/h3&gt;

&lt;p&gt;Appenders define where your log events will be delivered. The most common appenders are the Console and File Appenders. While useful and widely known, they may not fulfill your requirements. For example, you may want to write your logs in an asynchronous way or you may want to ship your logs over the network using appenders like the one for Syslog, like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;Appenders&amp;gt;
    &amp;lt;Console name="Console" target="SYSTEM_OUT"&amp;gt;
        &amp;lt;PatternLayout pattern="%d %level [%t] %c - %m%n"/&amp;gt;
    &amp;lt;/Console&amp;gt;
    &amp;lt;Syslog name="Syslog" host="logsene-syslog-receiver.sematext.com"
            port="514" protocol="TCP" format="RFC5424"
            appName="11111111-2222-3333-4444-555555555555"
            facility="LOCAL0" mdcId="mdc" newLine="true"/&amp;gt;
&amp;lt;/Appenders&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, keep in mind that using appenders like the one shown above makes your logging pipeline susceptible to network errors and communication disruptions. That may result in logs not being shipped to their destination which may not be acceptable. You also want to avoid logging affecting your system if the appender is designed in a blocking way. To learn more check our &lt;a href="https://sematext.com/blog/logging-libraries-vs-log-shippers/" rel="noopener noreferrer"&gt;Logging libraries vs Log shippers&lt;/a&gt; blog post.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Use Meaningful Messages
&lt;/h3&gt;

&lt;p&gt;One of the crucial things when it comes to creating logs, yet one of the not so easy ones is using meaningful messages. Your log events should include messages that are unique to the given situation, clearly describe them and inform the person reading them. Imagine a communication error occurred in your application. You might do it like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

LOGGER.warn("Communication error");


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But you could also create a message like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

LOGGER.warn("Error while sending documents to events Elasticsearch server, response code %d, response message %s. The message sending will be retried.", responseCode, responseMessage);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can easily see that the first message will inform the person looking at the logs about some communication issues. That person will probably have the context, the name of the logger, and the line number where the warning happened, but that is all. To get more context that person would have to look at the code, know which version of the code the error is related to, and so on. This is not fun and often not easy, and certainly not something one wants to be doing while trying to troubleshoot a production issue as quickly as possible.&lt;/p&gt;

&lt;p&gt;The second message is better. It provides exact information about what kind of communication error happened, what the application was doing at the time, what error code it got, and what the response from the remote server was. Finally, it also informs that sending the message will be retried. Working with such messages is definitely easier and more pleasant.&lt;/p&gt;

&lt;p&gt;Finally, think about the size and verbosity of the message. Don’t log information that is too verbose. This data needs to be stored somewhere in order to be useful. One very long message will not be a problem, but if that line is repeating hundreds of times in a minute and you have lots of verbose logs, keeping longer retention of such data may be problematic and, at the end of the day, will also cost more.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Logging Java Stack Traces
&lt;/h3&gt;

&lt;p&gt;One of the very important parts of Java logging are the Java stack traces. Have a look at the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

package com.sematext.blog.logging;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class Log4JExceptionNoThrowable {
    private static final Logger LOGGER = LogManager.getLogger(Log4JExceptionNoThrowable.class);

    public static void main(String[] args) {
        try {
            throw new IOException("This is an I/O error");
        } catch (IOException ioe) {
            LOGGER.error("Error while executing main thread");
        }
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above code will result in an exception being thrown and a log message that will be printed to the console with our default configuration will look as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

11:42:18.952 ERROR - Error while executing main thread


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see there is not a lot of information there. We only know that the problem occurred, but we don’t know where it happened, or what the problem was, etc. Not very informative.&lt;/p&gt;

&lt;p&gt;Now, look at the same code with a slightly modified logging statement:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

package com.sematext.blog.logging;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class Log4JException {
    private static final Logger LOGGER = LogManager.getLogger(Log4JException.class);

    public static void main(String[] args) {
        try {
            throw new IOException("This is an I/O error");
        } catch (IOException ioe) {
            LOGGER.error("Error while executing main thread", ioe);
        }
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, this time we’ve included the exception object itself in our log message:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

LOGGER.error("Error while executing main thread", ioe);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That would result in the following error log in the console with our default configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

11:30:17.527 ERROR - Error while executing main thread
java.io.IOException: This is an I/O error
    at com.sematext.blog.logging.Log4JException.main(Log4JException.java:13) [main/:?]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It contains relevant information – i.e. the name of the class, the method where the problem occurred, and finally the line number where the problem happened. Of course, in real-life situations, the stack traces will be longer, but you should include them to give you enough information for proper debugging.&lt;/p&gt;

&lt;p&gt;To learn more about how to handle Java stack traces with Logstash see &lt;a href="https://sematext.com/blog/handling-stack-traces-with-logstash/" rel="noopener noreferrer"&gt;Handling Multiline Stack Traces with Logstash&lt;/a&gt; or look at &lt;a href="https://sematext.com/docs/logagent/parser/" rel="noopener noreferrer"&gt;Logagent&lt;/a&gt; which can do that for you out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Logging Java Exceptions
&lt;/h3&gt;

&lt;p&gt;When dealing with Java exceptions and stack traces you shouldn’t only think about the whole stack trace, the lines where the problem appeared, and so on. You should also think about how not to deal with exceptions.&lt;/p&gt;

&lt;p&gt;Avoid silently ignoring exceptions. You don’t want to ignore something important. For example, do not do this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

try {
     throw new IOException("This is an I/O error");
} catch (IOException ioe) {
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Also, don’t just log an exception and throw it further. That means that you just pushed the problem up the execution stack. Avoid things like this as well:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

try {
    throw new IOException("This is an I/O error");
} catch (IOException ioe) {
    LOGGER.error("I/O error occurred during request processing", ioe);
    throw ioe;
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  6. Use Appropriate Log Level
&lt;/h3&gt;

&lt;p&gt;When writing your application code think twice about a given log message. Not every bit of information is equally important and not every unexpected situation is an error or a critical message. Also, using the logging levels consistently – information of a similar type should be on a similar severity level.&lt;/p&gt;

&lt;p&gt;Both &lt;a href="http://www.slf4j.org/" rel="noopener noreferrer"&gt;SLF4J&lt;/a&gt; facade and each Java logging framework that you will be using provide methods that can be used to provide a proper log level. For example:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

LOGGER.error("I/O error occurred during request processing", ioe);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  7. Log in JSON
&lt;/h3&gt;

&lt;p&gt;If we plan to log and look at the data manually in a file or the standard output then the planned logging will be more than fine. It is more user friendly – we are used to it. But that is only viable for very small applications and even then it is suggested to use something that will allow you to &lt;a href="https://sematext.com/metrics-and-logs/" rel="noopener noreferrer"&gt;correlate the metrics data with the logs&lt;/a&gt;. Doing such operations in a terminal window ain’t fun and sometimes it is simply not possible. If you want to store logs in the &lt;a href="https://sematext.com/guides/log-management/" rel="noopener noreferrer"&gt;log management&lt;/a&gt; and centralization system you should log in JSON. That’s because parsing doesn’t come for free – it usually means using regular expressions. Of course, you can pay that price in the log shipper, but why do that if you can easily log in JSON. Logging in JSON also means easy handling of stack traces, so yet another advantage. Well, you can also just log to a &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/" rel="noopener noreferrer"&gt;Syslog&lt;/a&gt; compatible destination, but that is a different story.&lt;/p&gt;

&lt;p&gt;In most cases, to enable logging in JSON in your Java logging framework it is enough to include the proper configuration. For example, let’s assume that we have the following log message included in our code:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

LOGGER.info("This is a log message that will be logged in JSON!");


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To configure &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4J 2&lt;/a&gt; to write log messages in JSON we would include the following configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;Configuration status="WARN"&amp;gt;
    &amp;lt;Appenders&amp;gt;
        &amp;lt;Console name="Console" target="SYSTEM_OUT"&amp;gt;
            &amp;lt;JSONLayout compact="true" eventEol="true"&amp;gt;
            &amp;lt;/JSONLayout&amp;gt;
        &amp;lt;/Console&amp;gt;
    &amp;lt;/Appenders&amp;gt;
    &amp;lt;Loggers&amp;gt;
        &amp;lt;Root level="info"&amp;gt;
            &amp;lt;AppenderRef ref="Console"/&amp;gt;
        &amp;lt;/Root&amp;gt;
    &amp;lt;/Loggers&amp;gt;
&amp;lt;/Configuration&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The result would look as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{"instant":{"epochSecond":1596030628,"nanoOfSecond":695758000},"thread":"main","level":"INFO","loggerName":"com.sematext.blog.logging.Log4J2JSON","message":"This is a log message that will be logged in JSON!","endOfBatch":false,"loggerFqcn":"org.apache.logging.slf4j.Log4jLogger","threadId":1,"threadPriority":5}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  8. Keep the Log Structure Consistent
&lt;/h3&gt;

&lt;p&gt;The structure of your log events should be consistent. This is not only true within a single application or set of microservices, but should be applied across your whole application stack. With similarly structured log events it will be easier to look into them, compare them, correlate them, or simply store them in a dedicated data store. It is easier to look into data coming from your systems when you know that they have common fields like severity and hostname, so you can easily slice and dice the data based on that information. For inspiration, have a look at &lt;a href="https://sematext.com/docs/tags/common-schema/" rel="noopener noreferrer"&gt;Sematext Common Schema&lt;/a&gt; even if you are not a Sematext user.&lt;/p&gt;

&lt;p&gt;Of course, keeping the structure is not always possible, because your full stack consists of externally developed servers, databases, search engines, queues, etc., each of which has their own set of logs and log formats. However, to keep your and your team’s sanity minimize the number of different log message structures that you can control.&lt;/p&gt;

&lt;p&gt;One way of keeping a common structure is to use the same pattern for your logs, at least the ones that are using the same logging framework. For example, if your applications and microservices use &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4J 2&lt;/a&gt; you could use a pattern like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;PatternLayout&amp;gt;
    &amp;lt;Pattern&amp;gt;%d %p [%t] %c{35}:%L - %m%n&amp;lt;/Pattern&amp;gt;
&amp;lt;/PatternLayout&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By using a single or a very limited set of patterns you can be sure that the number of log formats will remain small and manageable.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Add Context to Your Logs
&lt;/h3&gt;

&lt;p&gt;Information context is important and for us developers and DevOps a log message is information. Look at the following log entry:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[2020-06-29 16:25:34] [ERROR ] An error occurred!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We know that an error appeared somewhere in the application. We don’t know where it happened, we don’t know what kind of error it was, we only know when it happened. Now look at a message with slightly more contextual information:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[2020-06-29 16:25:34] [main] [ERROR ] com.sematext.blog.logging.ParsingErrorExample - A parsing error occurred for user with id 1234!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The same log record, but a lot more contextual information. We know the thread in which it happened, we know what class the error was generated at. We modified the message as well to include the user that the error happened for, so we can get back to the user if needed. We could also include additional information like diagnostic contexts. Think about what you need and include it.&lt;/p&gt;

&lt;p&gt;To include context information you don’t have to do much when it comes to the code that is responsible for generating the log message. For example, the &lt;a href="https://logging.apache.org/log4j/2.x/manual/layouts.html%23PatternLayout" rel="noopener noreferrer"&gt;PatternLayout&lt;/a&gt; in &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4J 2&lt;/a&gt; gives you all that you need to include the context information. You can go with a very simple pattern like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n"/&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That will result in a log message similar to the following one:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

17:13:08.059 INFO - This is the first INFO level log message!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But you can also include a pattern that will include way more information:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;PatternLayout pattern="%d{HH:mm:ss.SSS} %c %l %-5level - %msg%n"/&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That will result in a log message like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

17:24:01.710 com.sematext.blog.logging.Log4j2 com.sematext.blog.logging.Log4j2.main(Log4j2.java:12) INFO - This is the first INFO level log message!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  10. Java Logging in Containers
&lt;/h3&gt;

&lt;p&gt;Think about the environment your application is going to be running in. There is a difference in logging configuration when you are running your Java code in a VM or on a bare-metal machine, it is different when running it in a containerized environment, and of course, it is different when you run your Java or Kotlin code on an &lt;a href="https://github.com/sematext/sematext-logsene-android/" rel="noopener noreferrer"&gt;Android device&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To set up &lt;a href="https://sematext.com/blog/docker-logs-location/" rel="noopener noreferrer"&gt;logging in a containerized environment&lt;/a&gt; you need to choose the approach you want to take. You can use one of the provided &lt;a href="https://sematext.com/blog/docker-log-driver-alternatives/" rel="noopener noreferrer"&gt;logging drivers&lt;/a&gt; – like the &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;journald&lt;/a&gt;, &lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;logagent&lt;/a&gt;, Syslog, or JSON file. To do that, remember that your application shouldn’t write the log file to the container ephemeral storage, but to the standard output. That can be easily done by configuring your logging framework to write the log to the console. For example, with &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4J 2&lt;/a&gt; you would just use the following appender configuration:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;Appenders&amp;gt;
    &amp;lt;Console name="Console" target="SYSTEM_OUT"&amp;gt;
        &amp;lt;PatternLayout pattern="%d{HH:mm:ss.SSS} - %m %n"/&amp;gt;
    &amp;lt;/Console&amp;gt;
&amp;lt;/Appenders&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can also completely omit the logging drivers and ship logs directly to your centralized logs solution like our &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;Appenders&amp;gt;
    &amp;lt;Console name="Console" target="SYSTEM_OUT"&amp;gt;
        &amp;lt;PatternLayout pattern="%d %level [%t] %c - %m%n"/&amp;gt;
    &amp;lt;/Console&amp;gt;
    &amp;lt;Syslog name="Syslog" host="logsene-syslog-receiver.sematext.com"
            port="514" protocol="TCP" format="RFC5424"
            appName="11111111-2222-3333-4444-555555555555"
            facility="LOCAL0" mdcId="mdc" newLine="true"/&amp;gt;
&amp;lt;/Appenders&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  11. Don’t Log Too Much or Too Little
&lt;/h3&gt;

&lt;p&gt;As developers we tend to think that everything might be important – we tend to mark each step of our algorithm or business code as important. On the other hand, we sometimes do the opposite – we don’t add logging where we should or we log only FATAL and ERROR log levels. Both approaches will not do very well. When writing your code and adding logging, think about what will be important to see if the application is working properly and what will be important to be able to diagnose a wrong application state and fix it. Use this as your guiding light to decide what and where to log. Keep in mind that adding too many logs will end up in information fatigue and not having enough information will result in the inability to troubleshoot.&lt;/p&gt;
&lt;h3&gt;
  
  
  12. Keep the Audience in Mind
&lt;/h3&gt;

&lt;p&gt;In most cases, you will not be the only person looking at the logs. Always remember that. There are multiple actors that may be looking at the logs.&lt;/p&gt;

&lt;p&gt;The developer may be looking at the logs for troubleshooting or during debugging sessions. For such people, logs can be detailed, technical, and include very deep information related to how the system is running. Such a person will also have access to the code or will even know the code and you can assume that.&lt;/p&gt;

&lt;p&gt;Then there are DevOps. For them, log events will be needed for troubleshooting and should include information helpful in diagnostics. You can assume the knowledge of the system, its architecture, its components, and the configuration of the components, but you should not assume the knowledge about the code of the platform.&lt;/p&gt;

&lt;p&gt;Finally, your application logs may be read by your users themselves. In such a case, the logs should be descriptive enough to help fix the issue if that is even possible or give enough information to the support team helping the user. For example, using Sematext for monitoring involves installing and running a monitoring agent. If you are behind a very restrictive firewall and the agent cannot ship metrics to Sematext, it logs errors aimed that Sematext users themselves can look at, too.&lt;/p&gt;

&lt;p&gt;We could go further and identify even more actors who might be looking into logs, but this shortlist should give you a glimpse into what you should think about when writing your log messages.&lt;/p&gt;
&lt;h3&gt;
  
  
  13. Avoid Logging Sensitive Information
&lt;/h3&gt;

&lt;p&gt;Sensitive information shouldn’t be present in logs or should be masked. Passwords, credit card numbers, social security numbers, access tokens, and so on – all of that may be dangerous if leaked or accessed by those who shouldn’t see that. There are two things you ought to consider.&lt;/p&gt;

&lt;p&gt;Think whether sensitive information is truly essential for troubleshooting. Maybe instead of a credit card number, it is enough to keep the information about the transaction identifier and the date of the transaction? Maybe it is not necessary to keep the social security number in the logs when you can easily store the user identifier. Think about such situations, think about the data that you store, and only write sensitive data when it is really necessary.&lt;/p&gt;

&lt;p&gt;The second thing is shipping logs with sensitive information to a hosted logs service. There are very few exceptions where the following advice should not be followed. If your logs have and need to have sensitive information stored, mask or remove them before sending them to your centralized logs store. Most popular log shippers, like our own &lt;a href="https://sematext.com/logagent/" rel="noopener noreferrer"&gt;Logagent&lt;/a&gt;, include functionality that allows &lt;a href="https://sematext.com/docs/logagent/output-filter-removefields/" rel="noopener noreferrer"&gt;removal or masking of sensitive data&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, the masking of sensitive information can be done in the logging framework itself. Let’s look at how it can be done by extending &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Log4j 2&lt;/a&gt;. Our code that produces log events looks as follows (full example can be found at &lt;a href="https://github.com/sematext/blog-java_logging/tree/master/log4jmasking" rel="noopener noreferrer"&gt;Sematext Github&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

public class Log4J2Masking {
    private static Logger LOGGER = LoggerFactory.getLogger(Log4J2Masking.class);
    private static final Marker SENSITIVE_DATA_MARKER = MarkerFactory.getMarker("SENSITIVE_DATA_MARKER");

    public static void main(String[] args) {
        LOGGER.info("This is a log message without sensitive data");
        LOGGER.info(SENSITIVE_DATA_MARKER, "This is a a log message with credit card number 1234-4444-3333-1111 in it");
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you were to run the whole example from Github the output would be as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

21:20:42.099 - This is a log message without sensitive data
21:20:42.101 - This is a a log message with credit card number ****-****-****-**** in it


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can see that the credit card number was masked. This was done because we added a custom &lt;a href="https://logging.apache.org/log4j/2.x/manual/extending.html%23PatternConverters" rel="noopener noreferrer"&gt;Converter&lt;/a&gt; that checks if the given Marker is passed along the log event and tries to replace a defined pattern. The implementation of such Converter looks as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

@Plugin(name = "sample_logging_mask", category = "Converter")
@ConverterKeys("sc")
public class LoggingConverter extends LogEventPatternConverter {
    private static Pattern PATTERN = Pattern.compile("\\b([0-9]{4})-([0-9]{4})-([0-9]{4})-([0-9]{4})\\b");

    public LoggingConverter(String[] options) {
        super("sc", "sc");
    }

    public static LoggingConverter newInstance(final String[] options) {
        return new LoggingConverter(options);
    }

    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {
        String message = event.getMessage().getFormattedMessage();
        String maskedMessage = message;

        if (event.getMarker() != null &amp;amp;&amp;amp; "SENSITIVE_DATA_MARKER".compareToIgnoreCase(event.getMarker().getName()) == 0) {
            Matcher matcher = PATTERN.matcher(message);
            if (matcher.find()) {
                maskedMessage = matcher.replaceAll("****-****-****-****");
            }
        }

        toAppendTo.append(maskedMessage);
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is very simple and could be written in a more optimized way and should also handle all the possible credit cards number formats, but it is enough for this purpose.&lt;/p&gt;

&lt;p&gt;Before jumping into the code explanation I would also like to show you the &lt;strong&gt;log4j2.xml&lt;/strong&gt; configuration file for this example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;Configuration status="WARN" packages="com.sematext.blog.logging"&amp;gt;
    &amp;lt;Appenders&amp;gt;
        &amp;lt;Console name="Console" target="SYSTEM_OUT"&amp;gt;
            &amp;lt;PatternLayout pattern="%d{HH:mm:ss.SSS} - %sc %n"/&amp;gt;
        &amp;lt;/Console&amp;gt;
    &amp;lt;/Appenders&amp;gt;
    &amp;lt;Loggers&amp;gt;
        &amp;lt;Root level="info"&amp;gt;
            &amp;lt;AppenderRef ref="Console"/&amp;gt;
        &amp;lt;/Root&amp;gt;
    &amp;lt;/Loggers&amp;gt;
&amp;lt;/Configuration&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, we’ve added the packages attribute in our Configuration to tell the framework where to look for our converter. Then we’ve used the &lt;strong&gt;%sc&lt;/strong&gt; pattern to provide the log message. We do that because we can’t overwrite the default &lt;strong&gt;%m&lt;/strong&gt; pattern. Once Log4j2 finds our &lt;strong&gt;%sc&lt;/strong&gt; pattern it will use our converter which takes the formatted message of the log event and uses a simple regex and replaces the data if it was found. As simple as that.&lt;/p&gt;

&lt;p&gt;One thing to notice here is that we are using the Marker functionality. Regex matching is expensive and we don’t want to do that for every log message. That’s why we mark the log events that should be processed with the created Marker, so only the marked ones are checked.&lt;/p&gt;

&lt;h3&gt;
  
  
  14. Use a Log Management Solution to Centralize &amp;amp; Monitor Java Logs
&lt;/h3&gt;

&lt;p&gt;With the complexity of the applications, the volume of your logs will grow, too. You may get away with logging to a file and only using logs when troubleshooting is needed, but when the amount of data grows it quickly becomes difficult and slow to troubleshoot this way When this happens, consider using &lt;a href="https://sematext.com/logsene/" rel="noopener noreferrer"&gt;a log&lt;/a&gt; management solution to centralize and monitor your logs. You can either go for an in house solution based on the open-source software, like &lt;a href="https://sematext.com/guides/elk-stack/" rel="noopener noreferrer"&gt;Elastic Stack&lt;/a&gt;, or use one of the &lt;a href="https://sematext.com/blog/best-log-management-tools/" rel="noopener noreferrer"&gt;log management tools&lt;/a&gt; available on the market like &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt; or &lt;a href="https://sematext.com/enterprise/" rel="noopener noreferrer"&gt;Sematext Enterprise&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flua10oey54etpdeoquv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flua10oey54etpdeoquv0.png" alt="Sematext Cloud Logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A fully &lt;a href="https://sematext.com/guides/log-management/" rel="noopener noreferrer"&gt;managed log centralization&lt;/a&gt; solution will give you the freedom of not needing to manage yet another, usually quite complex, part of your infrastructure. Instead, you will be able to focus on your application and will need to set up only log shipping. You may want to include logs like JVM &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;garbage collection logs&lt;/a&gt; in your managed log solution. After &lt;a href="https://sematext.com/blog/java-garbage-collection/" rel="noopener noreferrer"&gt;turning them on&lt;/a&gt; for your applications and systems working on the JVM you will want to have them in a single place for correlation, analysis, and to help you &lt;a href="https://sematext.com/blog/java-garbage-collection-tuning/" rel="noopener noreferrer"&gt;tune the garbage collection&lt;/a&gt; in the JVM instances. Alert on logs, &lt;a href="https://sematext.com/blog/log-aggregation/" rel="noopener noreferrer"&gt;aggregate the data&lt;/a&gt;, save and re-run the queries, hook up your favorite incident management software. Correlating the &lt;a href="https://sematext.com/logsene/" rel="noopener noreferrer"&gt;logs&lt;/a&gt; data with &lt;a href="https://sematext.com/spm/" rel="noopener noreferrer"&gt;metrics&lt;/a&gt; coming from the &lt;a href="https://sematext.com/guides/java-monitoring/" rel="noopener noreferrer"&gt;JVM applications&lt;/a&gt;, system and &lt;a href="https://sematext.com/spm/" rel="noopener noreferrer"&gt;infrastructure&lt;/a&gt;, &lt;a href="https://sematext.com/experience/" rel="noopener noreferrer"&gt;real user&lt;/a&gt;, and &lt;a href="https://sematext.com/synthetic-monitoring/" rel="noopener noreferrer"&gt;API endpoints&lt;/a&gt; is something that platforms like &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt; are capable of. And of course, remember that application logs are not everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Incorporating each and every good practice may not be easy to implement right away, especially for applications that are already live and working in production. But if you take the time and roll the suggestions out one after another you will start seeing an increase in usefulness of your logs. Also, remember that at Sematext we do help organizations with their logging setups by offering &lt;a href="https://sematext.com/consulting/logging/" rel="noopener noreferrer"&gt;logging consulting&lt;/a&gt;, so reach out if you are having trouble and we will be happy to help.&lt;/p&gt;

</description>
      <category>java</category>
      <category>logging</category>
      <category>logs</category>
    </item>
    <item>
      <title>Node.js Monitoring in Production - Revised eBook</title>
      <dc:creator>Adnan Rahić</dc:creator>
      <pubDate>Fri, 28 Aug 2020 10:51:11 +0000</pubDate>
      <link>https://dev.to/sematext/node-js-monitoring-in-production-revised-ebook-4b9n</link>
      <guid>https://dev.to/sematext/node-js-monitoring-in-production-revised-ebook-4b9n</guid>
      <description>&lt;p&gt;Hey!&lt;/p&gt;

&lt;p&gt;Not so long ago I wrote my first ever eBook called &lt;a href="https://hubs.ly/H0hZ8rp0" rel="noopener noreferrer"&gt;Node.js Monitoring in Production&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few months ago I wrote another chapter and added it to the eBook. Now I want to share the revised version with all of you!&lt;/p&gt;

&lt;p&gt;Lots of love peeps! 🥰&lt;/p&gt;

&lt;p&gt;&lt;a href="https://hubs.ly/H0hZ8rp0" rel="noopener noreferrer"&gt;Here's the official download link!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope you like it! Feel free to let me know your thoughts in the comments below. Happy coding. :)&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>devops</category>
      <category>showdev</category>
    </item>
    <item>
      <title>15+ Best Cloud Monitoring Tools of 2020: Pros &amp; Cons Comparison</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Thu, 06 Aug 2020 10:28:01 +0000</pubDate>
      <link>https://dev.to/sematext/15-best-cloud-monitoring-tools-of-2020-pros-cons-comparison-35k</link>
      <guid>https://dev.to/sematext/15-best-cloud-monitoring-tools-of-2020-pros-cons-comparison-35k</guid>
      <description>&lt;p&gt;When providing services to your customers you need to keep an eye on everything that could impact your success with that – from low-level performance metrics to high-level business key performance indicators. From server-side logs to stack traces giving you full visibility into business and software processes that underpin your product. That’s where cloud monitoring tools and services come into play. They help you achieve full readiness of your infrastructure, applications, and make sure that your users and customers can use your platform to its full potential.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Is Cloud Monitoring?
&lt;/h1&gt;

&lt;p&gt;Cloud monitoring is a process of gaining observability into your cloud-based infrastructure, services, applications, and user experience. It allows you to observe the environment, review, and predict performance and availability of the whole infrastructure or drill into each piece of it on its own. Cloud monitoring works by collecting observability data, such as metrics, logs, traces, etc. from your whole IT infrastructure, analyzing it, and presenting it in a format understood by humans, like charts, graphs, and alerts, as well as machines via APIs&lt;/p&gt;

&lt;h1&gt;
  
  
  Best Cloud Monitoring Tools
&lt;/h1&gt;

&lt;p&gt;There are many types of tools that can help you gain full observability into your infrastructure, services, applications, website performance and health. Some help you with just one aspect of monitoring, while others give you full visibility into all of the key performance indicators, metrics, logs, traces, etc. Some you can set up easily and without talking to sales, others are more complex and involve a more traditional trial and sales process. Each solution has its pros and cons – sometimes the flexibility of a solution comes with a higher setup complication, while the setup and ease of use come with a limited set of features. As users, we need to choose the solution that’s the best fit for our needs and budget. In this post, we are going to explore the cloud monitoring tools that you should be aware of and that will let you know if your business and its IT operations are healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Sematext Cloud
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1AY0POEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lofaexo2b1o4f5bhrrho.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1AY0POEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lofaexo2b1o4f5bhrrho.jpg" alt="Sematext Cloud"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sematext.com/cloud/"&gt;Sematext Cloud&lt;/a&gt; and its on-premise version – &lt;a href="https://sematext.com/enterprise/"&gt;Sematext Enterprise&lt;/a&gt; – is a full observability solution that is easy to set up and that gives you in-depth visibility into your &lt;a href="https://sematext.com/spm/"&gt;IT infrastructure&lt;/a&gt;. Dashboards with key application and infrastructure (e.g., &lt;a href="https://sematext.com/database-monitoring"&gt;common databases&lt;/a&gt; and NoSQL stores, &lt;a href="https://sematext.com/server-monitoring/"&gt;servers&lt;/a&gt;, containers, etc.) come out of the box and can be customized. There is powerful &lt;a href="https://sematext.com/alerts/"&gt;alerting&lt;/a&gt; with anomaly detection and scheduling. Sematext Cloud is the solution that gives you both reactive and predictive monitoring with easy analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Auto-discovery of services enables hands-off auto-monitoring.&lt;/li&gt;
&lt;li&gt;Full-blown &lt;a href="https://sematext.com/logsene/"&gt;log management&lt;/a&gt; solution with filtering, full-text search, alerting, scheduled reporting, AWS S3, IBM Cloud, and Minio archiving integrations, Elasticsearch-compatible API and Syslog support.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sematext.com/experience/"&gt;Real user&lt;/a&gt; and &lt;a href="https://sematext.com/synthetic-monitoring/"&gt;synthetic monitoring&lt;/a&gt; for full visibility of how your users experience your frontend and how fast and healthy your APIs are.&lt;/li&gt;
&lt;li&gt;Comprehensive support for microservices and containerized environments – support for &lt;a href="https://sematext.com/kubernetes/"&gt;Kubernetes&lt;/a&gt;, &lt;a href="https://sematext.com/docker/"&gt;Docker&lt;/a&gt;, and Docker Swarm with ability to observe applications running in them, too; collection of their metrics, logs, and events.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sematext.com/network-monitoring/"&gt;Network&lt;/a&gt;, &lt;a href="https://sematext.com/database-monitoring/"&gt;database&lt;/a&gt;, &lt;a href="https://sematext.com/process-monitoring/"&gt;processes&lt;/a&gt;, and &lt;a href="https://sematext.com/inventory-monitoring/"&gt;inventory monitoring&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Alerting with anomaly detection and support for external notification services like PagerDuty, OpsGenie, VictorOps, WebHooks, etc.&lt;/li&gt;
&lt;li&gt;Powerful dashboarding capabilities for graphing virtually any data shipped to Sematext.&lt;/li&gt;
&lt;li&gt;Scheduled reporting.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Lots of out of the box &lt;a href="https://sematext.com/integrations"&gt;integrations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lightweight, open-sourced and pluggable agents. Quick setup.&lt;/li&gt;
&lt;li&gt;Powerful Machine Learning-based alerting and notifications system to quickly inform you about issues and potential problems with your environment.&lt;/li&gt;
&lt;li&gt;Elasticsearch and InfluxDB APIs allow for the integration of any tools that work with those, like &lt;a href="https://sematext.com/blog/getting-started-with-logstash/"&gt;Logstash&lt;/a&gt;, Filebeat, Fluentd, Logagent, Vector, etc..&lt;/li&gt;
&lt;li&gt;Easy correlation of performance metrics, logs, and various events.&lt;/li&gt;
&lt;li&gt;Collection of IT inventory – installed packages and their versions, detailed server info, container image inventory, etc.&lt;/li&gt;
&lt;li&gt;Straightforward pricing with free plans available, generous 30-days trial.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Limited support for transaction tracing.&lt;/li&gt;
&lt;li&gt;Lack of full-featured profiler.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://sematext.com/pricing/"&gt;pricing&lt;/a&gt; for each solution is straight forward. Each solution lets you choose a plan. As a matter of fact, pricing is super flexible for the cost-conscious — you have the flexibility of picking a different plan for each of your &lt;a href="https://sematext.com/docs/guide/app-guide/"&gt;Apps&lt;/a&gt;. For Logs there is a per-GB volume discount as your log volume or data retention goes up. Performance monitoring is metered by the hour, which makes it suitable for dynamic environments that scale up and down. Real user monitoring allows downsampling that can minimize your cost without sacrificing the value. Synthetic monitoring has a cheap pay-as-you-go option.&lt;/p&gt;

&lt;h2&gt;
  
  
  AppDynamics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tue_WWfD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tuzoxhihpnschtd9fqjw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tue_WWfD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tuzoxhihpnschtd9fqjw.jpg" alt="AppDynamics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Available in both software as a service and an on-premise model &lt;a href="https://www.appdynamics.com/"&gt;AppDynamics&lt;/a&gt; is more focused on large enterprises providing the ability to connect application performance metrics with infrastructure data, alerting, and &lt;a href="https://www.appdynamics.com/product/business-iq"&gt;business-level metrics&lt;/a&gt;. A combination of these allows you to monitor the whole stack that runs your services and gives you insights into your environment – from top-level transactions that are understood by the business executives to the code-level information useful for DevOps and developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;End-user monitoring with mobile and browser real user, synthetic, and internet of things monitoring.&lt;/li&gt;
&lt;li&gt;Infrastructure monitoring with network components, databases, and servers visibility providing information about status, utilization, and flow between each element.&lt;/li&gt;
&lt;li&gt;Business-focused dashboards and features provide visualizations and analysis of the connections between performance and &lt;a href="https://www.appdynamics.com/product/business-iq"&gt;business-oriented metrics&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Machine Learning supported anomaly detection and root cause analysis features.&lt;/li&gt;
&lt;li&gt;Alerting with email templating and period digest capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Very detailed information about the environment including versions, for example, JVM application startup parameters, JVM version, etc.&lt;/li&gt;
&lt;li&gt;Provides advanced features for various languages – for example, automatic leak detection and object instance tracking for the JVM based stack.&lt;/li&gt;
&lt;li&gt;Visibility into connections between the system components, environment elements, endpoint response times, and business transactions.&lt;/li&gt;
&lt;li&gt;Visibility into server and application metrics with up to code-level visibility and automated diagnostics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pricing: very expensive, complex, and non-transparent. Focused on more traditional high-touch sales model and selling to large enterprises.&lt;/li&gt;
&lt;li&gt;Installation of the agent requires manual downloading and starting of the agent – no one-line installation and setup command.&lt;/li&gt;
&lt;li&gt;Some of the basic metrics like system CPU, memory, and network utilization are not available in the lowest, paid plan tier.&lt;/li&gt;
&lt;li&gt;Slicing and dicing through the data is not as easy compared to some of the other tools mentioned in this summary that support rich dashboarding capabilities like Sematext, Datadog, or New Relic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Agent and feature-based &lt;a href="https://www.appdynamics.com/pricing"&gt;pricing&lt;/a&gt; is used which makes the pricing not transparent. The amount of money you will pay for the solution depends on the language your applications are written in and what functionalities you need and want to use from the platform. For example, visibility into the CPU, memory, and disk metrics requires the APM Advanced plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Datadog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--reHeRBT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5paap5n0dy0v1j186vg2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--reHeRBT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5paap5n0dy0v1j186vg2.jpg" alt="Datadog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Datadog is a full observability solution providing an extended set of features needed to monitor your infrastructure, applications, containers, network, logs, or even serverless features such as AWS lambdas. With the flexibility and functionality comes a price though – the configuration based agent installation may be time-consuming to set up (e.g. process monitoring requires agent config editing and agent restart) and quite some time may pass before you start seeing all the metrics, logs, and traces – all in one place for that full visibility into your application stack that you are after.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Application performance monitoring with a large number of integrations available and distributed tracing support.&lt;/li&gt;
&lt;li&gt;Logs centralization and analysis.&lt;/li&gt;
&lt;li&gt;Real user and synthetics monitoring.&lt;/li&gt;
&lt;li&gt;Network and host monitoring.&lt;/li&gt;
&lt;li&gt;Dashboard framework allows building of virtually everything out of the provided metrics and logs and sharing those.&lt;/li&gt;
&lt;li&gt;Alerting with machine learning capabilities.&lt;/li&gt;
&lt;li&gt;Collaboration tools for team-based discussions.&lt;/li&gt;
&lt;li&gt;API allowing to work with the data, tags, and dashboards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Full observability solution – metric, logs, security, real user, and synthetics all in one.&lt;/li&gt;
&lt;li&gt;Infrastructure monitoring including hosts, containers, processes, networks, and serverless capabilities.&lt;/li&gt;
&lt;li&gt;Rich logs integration including applications, containers, cloud providers, clients, and common log shippers.&lt;/li&gt;
&lt;li&gt;Powerful and very flexible data analysis features with alerts and custom dashboards.&lt;/li&gt;
&lt;li&gt;Provides API allowing interaction with the data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Overwhelming for newcomers with all the installation steps needed for anything beyond basic metrics.&lt;/li&gt;
&lt;li&gt;Not a lot of pre-built dashboards compared to others. New users have to invest quite a bit of time to understand metrics and build dashboards before being able to make full use of the solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Feature, host, and volume-based &lt;a href="https://www.datadoghq.com/pricing/"&gt;pricing&lt;/a&gt; combined together – each part of the solution is priced differently that can be billed annually or on-demand. The on-demand billing makes the solution about 17 – 20% more expensive than the annual pricing at the time of this writing. Pay close attention to your bill. We’ve seen a number of reports where people were surprised by bill items or amounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Relic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gEDA8GbT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rhlypzncix9a52ps9vb8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gEDA8GbT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/rhlypzncix9a52ps9vb8.jpg" alt="New Relic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;New Relic as a full-stack observability solution is available in software-as-a-service model. Its monitoring capabilities include application performance monitoring with rich dashboarding support, distributed tracing support, logs along with real user and synthetics monitoring for the top to bottom visibility. Even though the agents require manual steps to download and install they are robust and reliable with a wide range of common programming languages support which is a big advantage of New Relic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://newrelic.com/products/application-monitoring%20rel="&gt;Application Performance Monitoring&lt;/a&gt; with dashboarding and support for commonly used languages including C++.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://newrelic.com/products/logs%20rel="&gt;Log centralization&lt;/a&gt; and analysis.&lt;/li&gt;
&lt;li&gt;Integrated alerting with anomaly detection.&lt;/li&gt;
&lt;li&gt;Rich and powerful query language – NRQL.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://newrelic.com/products/browser-monitoring"&gt;Real user&lt;/a&gt; and &lt;a href="https://newrelic.com/products/synthetics"&gt;synthetics&lt;/a&gt; monitoring.&lt;/li&gt;
&lt;li&gt;Distributed tracing allowing you to understand what is happening from top to bottom.&lt;/li&gt;
&lt;li&gt;Integration with most known cloud providers such as AWS, Azure, and Google Cloud Platform.&lt;/li&gt;
&lt;li&gt;Business level metrics support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Visibility into the whole system, not only when using physical servers or virtual machines, but also when dealing with containers and microservices.&lt;/li&gt;
&lt;li&gt;Ability to connect business-level metrics together with performance to correlate them together.&lt;/li&gt;
&lt;li&gt;Error analytics tool for quick and efficient issues analysis, like site errors or downtime.&lt;/li&gt;
&lt;li&gt;Rich visualization support allowing to graph metrics, logs, and NRQL queries.&lt;/li&gt;
&lt;li&gt;Ability to define the correlation between alerts and defined logic to reduce alert noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The platform itself doesn’t provide agent management functionality, which leads to additional work related to installation and configuration, especially on a larger scale.&lt;/li&gt;
&lt;li&gt;Inconsistent UI: some parts of the product use the legacy interface, while others are already a part of NewRelic One.&lt;/li&gt;
&lt;li&gt;The log management part of the solution is still young.&lt;/li&gt;
&lt;li&gt;Lack of a single pricing page for all features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Annual and monthly compute unit or host-based pricing and depends on the features (for example: &lt;a href="https://newrelic.com/products/application-monitoring/pricing"&gt;APM pricing&lt;/a&gt;, &lt;a href="https://newrelic.com/products/infrastructure/pricing"&gt;infrastructure pricing&lt;/a&gt;, &lt;a href="https://newrelic.com/products/synthetics/pricing"&gt;synthetic pricing&lt;/a&gt;). For small services, the computing units may be the best option as they are calculated as the total number of CPUs with the amount of RAM your system has, multiplied by the number of running hours. For example, the infrastructure part of New Relic uses only compute units pricing, while the APM can be charged on both host and compute units-based pricing. This may be confusing and requires additional calculations if you want to control your costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Dynatrace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y9Hd4RbU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nt8moghw5ku766ubpnsp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y9Hd4RbU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nt8moghw5ku766ubpnsp.jpg" alt="Dynatrace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dynatrace is a full-stack observability solution that introduces a user-friendly approach to monitoring your applications, infrastructure, and logs. It supports a single running agent that, once installed, can be controlled via Dynatrace UI making monitoring easy and pleasant to work with. Available in both software as a service and on-premise models it will fulfill most of your monitoring needs when it comes to application performance monitoring, real users, logs and infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.dynatrace.com/platform/application-performance-management/"&gt;Application performance monitoring&lt;/a&gt; with dashboarding and rich integrations for commonly used tools and code-level tracing.&lt;/li&gt;
&lt;li&gt;First-class &lt;a href="https://www.dynatrace.com/platform/log-monitoring/"&gt;Log analysis&lt;/a&gt; support with automatic detection of the common system and application log types.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dynatrace.com/platform/real-user-monitoring/"&gt;Real user&lt;/a&gt; and &lt;a href="https://www.dynatrace.com/platform/synthetic-monitoring/"&gt;synthetic&lt;/a&gt; monitoring.&lt;/li&gt;
&lt;li&gt;Diagnostic tools allow taking memory dumps, exceptions and CPU analysis, top database, and web requests.&lt;/li&gt;
&lt;li&gt;Docker, Kubernetes, and OpenShift integrations.&lt;/li&gt;
&lt;li&gt;Support for common cloud providers like Amazon Web Services, Microsoft Azure, and Google Cloud Platform.&lt;/li&gt;
&lt;li&gt;A virtual assistant can make your life easier when dealing with common questions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple and intuitive agent installation with UI guidance for new users with demo data to get to know the product faster.&lt;/li&gt;
&lt;li&gt;Ease of integration to gain visibility into the logs of your systems and applications – almost everything is doable from the UI.&lt;/li&gt;
&lt;li&gt;Easy to navigate and powerful top to bottom view of the whole stack – from the mobile/web application through the middle tier up to the database level.&lt;/li&gt;
&lt;li&gt;Dedicated problem-solving functionalities to help in quick and efficient problem finding.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Lots of options can be overwhelming to start with, but the solution tries to do its best to help new users.&lt;/li&gt;
&lt;li&gt;Business metrics analysis is still limited compared to AppDynamics and Datadog, for example.&lt;/li&gt;
&lt;li&gt;Serverless offering is limited when compared to other solutions on the market, like Datadog, New Relic, and AppDynamics.&lt;/li&gt;
&lt;li&gt;Pricing information is only available once you sign up.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Pricing is organized around features. The application performance monitoring pricing is tied to hosts and the amount of memory available on a host. Each 16GB is a host unit and the price is calculated on the basis of the number of host units in an hour. The real user monitoring price is calculated based on the number of sessions, while the synthetics monitoring pricing is based on the number of actions. Finally, the logs part of the solution is calculated based on the volume, similar to other vendors covered in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Sumo Logic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FBNJb6YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n92fs3cjcdyvzzrtz9lz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FBNJb6YF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n92fs3cjcdyvzzrtz9lz.jpg" alt="Sumo Logic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sumo Logic is an observability solution with strong focus on working with logs and it does that very well. With tools like LogReduce and LogCompare you can not only view the logs from a given time period but also reduce the volume of data you need to analyze or even compare periods to find interesting discrepancies and anomalies. Combining that with metrics and security gives a great tool that will fulfill the observability needs for your environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Log analysis with the &lt;a href="https://www.sumologic.com/blog/what-is-logreduce/"&gt;LogReduce&lt;/a&gt; algorithm allows clustering of similar messages and &lt;a href="https://help.sumologic.com/05Search/LogCompare"&gt;LogCompare&lt;/a&gt; lets you compare data from two time periods.&lt;/li&gt;
&lt;li&gt;Field extraction enables rule-based data extraction from unstructured data.&lt;/li&gt;
&lt;li&gt;Application performance monitoring with real-time alerting and dashboarding.&lt;/li&gt;
&lt;li&gt;Scheduled views for running your queries periodically.&lt;/li&gt;
&lt;li&gt;Cloud security features for common cloud providers and SaaS solutions with PCI compliance and integrated threat intelligence.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User-friendly interface that doesn’t overwhelm novice users and is still usable for experienced ones.&lt;/li&gt;
&lt;li&gt;Ability to reduce the number of similar logs at read-time and compare periods of time together which can help to spot differences, anomalies, and track down problems quickly.&lt;/li&gt;
&lt;li&gt;Possibility to extract fields from unstructured data allows you to drop the processing component from your local pipeline and move it to the vendor side.&lt;/li&gt;
&lt;li&gt;Limited free tier available that may be enough for very small companies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pricing may be confusing and may be hard to pre-calculate when using Cloud Flex credits and larger environments.&lt;/li&gt;
&lt;li&gt;A limited number of out of the box charts compared to the competition.&lt;/li&gt;
&lt;li&gt;Primarily focused on logs puts them at a disadvantage if you are looking for a full-stack observility solution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Credit and feature-based &lt;a href="https://www.sumologic.com/pricing/us/"&gt;pricing&lt;/a&gt; with a limited free tier is available. A credit is a unit of utilization for ingested data – logs and metrics. The needed features dictate the price of each credit unit – the more features of the platform you need and will use, the more expensive the credit will be. Please keep in mind that the price also depends on the location you want to use. For example, at the time of this writing, the Ireland location was more expensive compared to North America.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. CA Unified Infrastructure Monitoring (UIM)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mqYwcxAP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eus3hs0h84xfegv1j0hi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mqYwcxAP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eus3hs0h84xfegv1j0hi.jpg" alt="CA Unified Infrastructure Monitoring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Available in both the SaaS and on-premise models, targeted at the enterprise customers the DX Infrastructure Manager, formerly called CA Unified Infrastructure Monitoring is a unified tool that allows you to get observability into your hybrid cloud, services, applications, and infrastructural elements like switches, routers and storage devices. With the actionable log analytics, out of the box dashboard, and alerting with anomaly detection algorithms the solution will give you retrospective and proactive views over your IT environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Monitoring with various integrations supporting common infrastructure provides and services including packaged applications such as Office 365 and tools like Salesforce Service Cloud.&lt;/li&gt;
&lt;li&gt;Log analytics with actionable, out of the box dashboards and rich visualization support.&lt;/li&gt;
&lt;li&gt;Alerting with anomaly detection and dynamic thresholds.&lt;/li&gt;
&lt;li&gt;Reporting with business-level metrics support and scheduling capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Easy deployment and configuration with configurable automatic service discovery.&lt;/li&gt;
&lt;li&gt;Templates support which allows you to build templates per environment, devices, and more.&lt;/li&gt;
&lt;li&gt;Advanced correlations for hybrid infrastructures.&lt;/li&gt;
&lt;li&gt;In-depth monitoring of the whole infrastructure with the help of various integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Non-transparent pricing — the pricing is not available on the web site.&lt;/li&gt;
&lt;li&gt;A limited number of alert notification destinations compared to other competitors.&lt;/li&gt;
&lt;li&gt;May be considered complicated for novice users.&lt;/li&gt;
&lt;li&gt;Targeted for enterprise customers.&lt;/li&gt;
&lt;li&gt;Dated UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;At the time of this writing the pricing was not publicly available on the vendor’s site.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Site 24×7
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZjA5Iitu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/reunjkx1ioa7v6pejbms.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZjA5Iitu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/reunjkx1ioa7v6pejbms.jpg" alt="Site 24x7"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Site 24×7 is an observability solution providing all that is needed to get full visibility into your website’s health, application performance, infrastructure, and network gear. Both when it comes to metrics and logs. Set up alerts based on advanced rules to limit down the alerts fatigue and get insights from your mobile applications. Monitor servers and over 50 common technologies running inside your environment including common and widely used Apache or MySQL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.site24x7.com/web-site-performance.html"&gt;Website monitoring&lt;/a&gt; with the support for monitoring HTTP services, DNS and FTP servers, SMTP and POP servers, URLs, and REST APIs available both publicly and in private networks.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.site24x7.com/server-monitoring.html"&gt;Server monitoring&lt;/a&gt; with support for Microsoft Windows and Linux and over 50 common technologies plugins, like MySQL or Apache.&lt;/li&gt;
&lt;li&gt;Full featured &lt;a href="https://www.site24x7.com/network-monitoring.html"&gt;network monitoring&lt;/a&gt; with routers, switches, firewalls, load balancers, UPS, and storage support.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.site24x7.com/application-performance-monitoring.html"&gt;Application performance&lt;/a&gt; monitoring and log management with support for server, desktop, and mobile applications and alerting capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.site24x7.com/cloud-monitoring.html"&gt;Cloud monitoring&lt;/a&gt; with support for hybrid cloud infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Quick and easy agent installation.&lt;/li&gt;
&lt;li&gt;Monitoring for various technologies with alerting support based on complex rules.&lt;/li&gt;
&lt;li&gt;Full observability with visibility from your website performance and health up to network-level devices like switches and routers.&lt;/li&gt;
&lt;li&gt;Custom dashboarding support lets you build your own views into the servers, applications, websites, servers, and cloud environments.&lt;/li&gt;
&lt;li&gt;Pluggable server monitoring allows you to write your own plugins where needed.&lt;/li&gt;
&lt;li&gt;Free, limited uptime and server monitoring which might be enough for personal needs or small companies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The number of features can be overwhelming for novice users.&lt;/li&gt;
&lt;li&gt;It can be time-consuming when setting up in a larger environment because of the lack of autodiscovery.&lt;/li&gt;
&lt;li&gt;A limited number of technologies when it comes to server monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.site24x7.com/site24x7-pricing.html"&gt;pricing&lt;/a&gt; depends on the parts of the product that you will use with the free uptime monitoring for a small number of websites and servers available. The infrastructure monitoring starts with the 9 euro per month when billed annually for up to 10 servers, 500MB of logs, and 100K page views for a single site. You can buy additional add-ons for a monthly fee. You can also go for pure website monitoring or application performance monitoring or so-called “All-in-one” plan, which covers all the features of the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Zabbix
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GCYGFgmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p5070hv3h1o5e17nf053.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GCYGFgmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/p5070hv3h1o5e17nf053.jpg" alt="Zabbix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open-sourced monitoring tool capable of real-time monitoring large scale enterprises and small companies. If you are looking for a solution with a large community, well supported, and free you should look at Zabbix. Its multi-system, small footprint agents allow you to gather key performance indicators across your environment and use them as a source for your dashboards and alerts. With the template-based setup and auto-discovery you can speed up even the largest setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-system, small footprint agent allowing to gather crucial &lt;a href="https://www.zabbix.com/features#metric_collection"&gt;metrics&lt;/a&gt; with support for SNMP and IPMI.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.zabbix.com/features#problem_detection"&gt;Problem detection&lt;/a&gt; and prediction mechanism with flexible thresholds and severity levels defining their importance.&lt;/li&gt;
&lt;li&gt;Multi-lingual, multi-tenant, flexible UI with &lt;a href="https://www.zabbix.com/features#visualization"&gt;dashboarding&lt;/a&gt; capabilities and geolocation support for large organizations with data centers spread around the world.&lt;/li&gt;
&lt;li&gt;Support for adjustable &lt;a href="https://www.zabbix.com/features#notification"&gt;notifications&lt;/a&gt; with out of the box support for email, SMS, Slack, Hipchat and XMPP and escalation workflow.&lt;/li&gt;
&lt;li&gt;Template-based host management and &lt;a href="https://www.zabbix.com/features#auto_discovery"&gt;auto-discovery&lt;/a&gt; for monitoring large environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Well known, open-sourced, and free with a large community and commercial support.&lt;/li&gt;
&lt;li&gt;Wide functionality allowing to monitor virtually everything.&lt;/li&gt;
&lt;li&gt;It can be easily integrated with other visualization tools like Grafana.&lt;/li&gt;
&lt;li&gt;Easily extensible for support for technologies and infrastructure elements not covered out of the box.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;As an open-sourced and completely free solution, you need to host it yourself and maintain it, meaning paying for the team that will install and manage it.&lt;/li&gt;
&lt;li&gt;Initial setup can be tedious and not so obvious and requires knowledge, not only about the platform but also about the applications, servers, and infrastructure elements that you plan on monitoring making the initial step quite steep.&lt;/li&gt;
&lt;li&gt;Lack of dedicated functionality to monitor user experience, synthetic monitoring and no transaction tracing support.&lt;/li&gt;
&lt;li&gt;If you are looking for a software-as-a-service solution, Zabbix Cloud is coming, but as of this writing it is still in beta.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Zabbix is open-sourced and free. You can subscribe for support, consultancy, and training around it though if you would like to quickly and efficiently extend your knowledge about the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Stackify Retrace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9tLudxCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98bsuu0fhke8vpobiyzy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9tLudxCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/98bsuu0fhke8vpobiyzy.jpg" alt="Stackify Retrace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stackify Retrace is a developer-centric solution providing users full visibility into their applications and infrastructure elements. With the availability of application performance monitoring, centralized logging, error reporting, and transaction tracing it is easy for a developer to connect pieces of information together when troubleshooting. All of that with help from the platform which connects those pieces together gluing the automated transaction tracing with the relevant logs and error data and proving the integrated profiler to give the top to bottom insight into the business transaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Centralized &lt;a href="https://stackify.com/retrace-log-management/"&gt;logging&lt;/a&gt; combined with &lt;a href="https://stackify.com/retrace-error-monitoring/"&gt;error&lt;/a&gt; reporting.&lt;/li&gt;
&lt;li&gt;Transaction tracing and &lt;a href="https://stackify.com/what-is-code-profiling/"&gt;code profiling&lt;/a&gt; with automatic instrumentalization for databases like MySQL, PostgreSQL, Oracle, SQL Server, and common NoSQL solutions like MongoDB and Elasticsearch.&lt;/li&gt;
&lt;li&gt;Key &lt;a href="https://stackify.com/retrace-application-performance-management/"&gt;performance metrics monitoring&lt;/a&gt; for your &lt;a href="https://stackify.com/retrace-app-monitoring/"&gt;applications&lt;/a&gt; with alerting and notifications support.&lt;/li&gt;
&lt;li&gt;Server monitoring gives you insight into the most useful metrics like uptime, CPU &amp;amp; memory utilization, disk space usage, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Top to bottom view starting with the web requests and ending at the relevant log message connected together with the transaction trace.&lt;/li&gt;
&lt;li&gt;Integrated profiler with out of the box instrumentalization for common system elements like database or NoSQL store.&lt;/li&gt;
&lt;li&gt;In-line log and error data inclusion in tracing information makes it super easy to connect information together for fast troubleshooting.&lt;/li&gt;
&lt;li&gt;Support for custom dashboards and reports.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No native support for Google Cloud at the time of writing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackify.com/retrace-real-user-monitoring/"&gt;Real user monitoring&lt;/a&gt; “coming soon” at the time of writing.&lt;/li&gt;
&lt;li&gt;UI reminiscent of Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://stackify.com/pricing/"&gt;pricing&lt;/a&gt; is based on data volume and is provided in three tiers – Essentials, Standard, and Enterprise. The Essentials package starts at $79/month allowing for 7 days of logs and traces retention, with up to 500k traces and 2m logs and up to 8 days of summary data retention with all the standard features provided. The Standard plan starts from $199 with additional features available for an appropriate higher price..&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Zenoss
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--StlS_Ae2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ku1o4y9w74tmk8inu0gh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--StlS_Ae2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ku1o4y9w74tmk8inu0gh.jpg" alt="Zenoss"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Multi-vendor infrastructure monitoring with support for end-to-end troubleshooting and real-time dependency mapping. With support for server monitoring including coming metrics, health and excellent network monitoring the Zenoss platform gives you visibility into your infrastructure, no matter if it is a private, hybrid, or a public cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.zenoss.com/product/converged-infrastructure-monitoring"&gt;Infrastructure monitoring&lt;/a&gt; with the support for public, private, and hybrid &lt;a href="https://www.zenoss.com/product/cloud-monitoring"&gt;clouds&lt;/a&gt; and real-time dependency mapping.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.zenoss.com/product/server-monitoring"&gt;Server monitoring&lt;/a&gt; with support for common metrics, health, physical sensors like temperature sensors, file systems, processes, network interfaces, and routes monitoring.&lt;/li&gt;
&lt;li&gt;Application performance monitoring available via ZenPacks with support for incident root cause analysis and metrics importance voting along with containers and microservices support.&lt;/li&gt;
&lt;li&gt;Support for &lt;a href="https://www.zenoss.com/solutions/log-analytics"&gt;logs&lt;/a&gt; with the support of log format unification.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-vendor support for a wide variety of hardware and software infrastructure elements.&lt;/li&gt;
&lt;li&gt;Automatic discovery for dynamic environments like &lt;a href="https://www.zenoss.com/product/container-monitoring-microservices"&gt;containers and microservices&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Extensibility via ZenPacks – available both as driven by the community and commercial extensions with SDK allowing you to develop new extensions easier.&lt;/li&gt;
&lt;li&gt;The self-managed, limited &lt;a href="https://www.zenoss.com/get-started"&gt;community version&lt;/a&gt; of the platform available as a solution with basic functionality and minimum scale.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Application performance monitoring available via ZenPacks extension or integration with third-party services.&lt;/li&gt;
&lt;li&gt;Available only in the on-premise model with no free trial available which makes it hard to test the platform.&lt;/li&gt;
&lt;li&gt;No features like real user monitoring, synthetic monitoring or transaction tracing.&lt;/li&gt;
&lt;li&gt;Focused on medium and large customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;At the time of writing the pricing was not publicly available on the vendor’s site, but one thing worth noting is the availability of the community version of the solution allowing you to install a limited, self-managed version of the platform.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When using Amazon Web Services, Google Cloud Platform, or Microsoft Azure you can rely on the tools provided by those platforms. The cloud provider dedicated solutions may not be as powerful as the platforms that we discussed above, but they provide insight into the metrics, logs, and infrastructure data. They give us not only visibility into the metrics but also proactive monitoring like alerts and health checks that you can use to configure the basic monitoring. If you are using a cloud solution from Amazon, Microsoft, or Google and you would like to use monitoring provided by those companies have a look at what they offer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  12. Amazon CloudWatch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k7yZ0urb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tx5co9tm3ftvjbbky640.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k7yZ0urb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tx5co9tm3ftvjbbky640.jpg" alt="Amazon CloudWatch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/cloudwatch/"&gt;Amazon CloudWatch&lt;/a&gt; is primarily aimed at customers using Amazon Web Services, but can also read metrics from statsd and collectd providing a way to ship custom metrics to the platform. By default, it provides an out of the box monitoring for your AWS infrastructure, services, and applications. With the integrated logs support and synthetics monitoring, it allows the users to set up basic monitoring quickly to give insights into the whole environment that is living in the Amazon ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;View metrics and logs of your infrastructure, services, and applications.&lt;/li&gt;
&lt;li&gt;Insights into events coming from your AWS environment.&lt;/li&gt;
&lt;li&gt;Service map and tracing support via AWS X-Ray.&lt;/li&gt;
&lt;li&gt;Synthetic service for web application monitoring.&lt;/li&gt;
&lt;li&gt;Alerting with anomaly detection on metrics and logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Available out of the box for Amazon Web Services Users.&lt;/li&gt;
&lt;li&gt;Support for custom metrics, so if you would like to stick to CloudWatch you can easily keep all your metrics there.&lt;/li&gt;
&lt;li&gt;Possibility to graph billing-related information and have that under control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Limited dashboarding and visualization capabilities.&lt;/li&gt;
&lt;li&gt;A limited number of dashboards that can be created in the free tier – if you have more than three dashboards will cost you $3.00 per month.&lt;/li&gt;
&lt;li&gt;Limited metrics granularity even when going for the paid service.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Volume-based &lt;a href="https://aws.amazon.com/cloudwatch/pricing/"&gt;pricing&lt;/a&gt; – you pay for what you want to have visibility into and how detailed it is. Free tier enables monitoring of your AWS services with 5-minute metric granularity. The free tier is also effective for services like EBS volumes, RDS DB instances, and Elastic Load Balancers. It covers up to ten metrics and then alarms per month. In addition, the free tier includes up to 5GB logs per month, 3 dashboards, and 100 runs of synthetic monitors per month. The paid tier price is based on usage. For example, for metrics, the one-minute granularity metrics starts at $0.30 per metric per month for the first 10,000 metrics and go as low as $0.02 per metric per month when sending over one million metrics. With logs the situation is similar – the more you send the less you pay per gigabyte of data.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Azure Monitor
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uBikTsjT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3v0c3en4nd42t5skrvfj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uBikTsjT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3v0c3en4nd42t5skrvfj.jpg" alt="Azure Monitor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://azure.microsoft.com/en-us/services/monitor/#partners"&gt;Azure Monitor&lt;/a&gt; a solution primarily focused on monitoring the services located in the Microsoft Azure cloud services, but support custom metrics for resources outside of the cloud. It provides a full-featured observability solution giving you deep insights into your infrastructure, services, applications, and Azure resources with powerful dashboards, BI support, and alerting that will automatically notify you when needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Monitoring for your &lt;a href="https://azure.microsoft.com/en-us/"&gt;Microsoft Azure&lt;/a&gt; resources, services, first-party solutions, and custom metrics sent by your applications.&lt;/li&gt;
&lt;li&gt;Detailed infrastructure monitoring for deep insight into the metrics.&lt;/li&gt;
&lt;li&gt;Network activity, layout, and services layout visualization and monitoring.&lt;/li&gt;
&lt;li&gt;Support for alerts and autoscaling based on the metrics and logs.&lt;/li&gt;
&lt;li&gt;Powerful dashboarding capabilities with workbooks and BI support.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Available out of the box for &lt;a href="https://azure.microsoft.com/en-us/"&gt;Microsoft Azure&lt;/a&gt; users.&lt;/li&gt;
&lt;li&gt;Azure resources, services, and first-party solutions expose their metrics in the free tier and other signals like logs and alerts have a free tier available.&lt;/li&gt;
&lt;li&gt;Support for workbooks and BI allows to connect business-level metrics with the signals coming from the services and infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It may be complicated and overwhelming for users that just started with Azure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The Azure Monitor &lt;a href="https://azure.microsoft.com/en-us/pricing/details/monitor/"&gt;pricing&lt;/a&gt; is based on the volume of the ingested data or reserved capacity. Selected metrics from the Azure resources, services, and first-party solutions are free. Custom metrics are paid once you pass the 150MB per month. Similar to other cloud vendors you pay less per unit of data the more data you send. The logs have the option to pay as you go which gives you up to 5GB of logs per billing account per month free and then $2.76 per GB of data. You can also go for reserved data – for example, 100GB of data per day will cost you $219.52 daily. Other monitoring elements are priced in a similar way with small or no free tier available.&lt;/p&gt;

&lt;h2&gt;
  
  
  14. Google Stackdriver
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_usE4o-b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kzj1ypgj843wi2boifxb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_usE4o-b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/kzj1ypgj843wi2boifxb.jpg" alt="Google Stackdriver"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Formerly &lt;a href="https://cloud.google.com/products/operations"&gt;Stackdriver Google Cloud&lt;/a&gt; operations suite is primarily focused to give the users of Google Cloud platform the insights into the infrastructure and application performance, but it also supports custom metrics and other cloud providers like AWS. The platform provides metrics, logs, and traces support along with the visibility into Google Cloud platform audit logs giving you the full visibility of what is happening inside your GCP account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Metrics and dashboards allowing visibility into the performance of your services with alerting.&lt;/li&gt;
&lt;li&gt;Health check monitoring for web applications and applications that can be accessed from the internet with uptime monitoring.&lt;/li&gt;
&lt;li&gt;Support for logs and logs routing with error reporting and alerting.&lt;/li&gt;
&lt;li&gt;Per-URL statistics based on distributed tracing for App Engine.&lt;/li&gt;
&lt;li&gt;Audit logs for visibility into security-related events in your Google Cloud account.&lt;/li&gt;
&lt;li&gt;Production debugging and profiling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rich visualization support out of the box for Google Cloud platform users.&lt;/li&gt;
&lt;li&gt;Free tier available.&lt;/li&gt;
&lt;li&gt;Support for sending data to third-party providers if they provide an integration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Requires a manual cloud monitoring agent install, before getting visibility into the metrics, compared to AWS CloudWatch where this is not needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;Similar to Amazon CloudWatch and Microsoft Azure the &lt;a href="https://cloud.google.com/stackdriver/pricing"&gt;pricing&lt;/a&gt; is based on the amount of data your services and applications are generating and sending to the platform. The free tier includes 150MB metrics per billing account, 50GB of logs per project, 1 million API calls per project, 2.5 million spans ingested per project and 25 million spans scanned per project. Everything above that falls into the paid tier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most of the tools that we’ve discussed &lt;strong&gt;provide a form of alerting and reporting&lt;/strong&gt;. Those are usually limited to a number of methods, like e-mail or text messages to your mobile, sometimes other common destinations. Usually, we don’t see scheduling, automation, and workflow control in the monitoring tools themselves. Because of that, &lt;strong&gt;the observability solutions provide &lt;a href="https://sematext.com/integrations/"&gt;integrations&lt;/a&gt; with third-party incident alerting and reporting tools filling the communication gap&lt;/strong&gt; and providing additional features like event automation and triage, noise suppression, alerts, and notifications centralization and lots of destinations where the information can be sent to. Let’s see what tools can provide such functionalities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  15. PagerDuty
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TW2tKkBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qfvwxf0vgdzy3vm0xawr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TW2tKkBX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qfvwxf0vgdzy3vm0xawr.jpg" alt="PagerDuty"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The all in one alert and notification management and centralization solution. The &lt;a href="https://www.pagerduty.com/platform/"&gt;PagerDuty&lt;/a&gt; provides the place where you can centralize notifications coming from various places, organize them, assign, automate, and send to virtually any destination you may think of. It not only provides a simple way of viewing and forwarding the data but also automates incident response, schedule on-call, and escalate incidents.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;On-call &lt;a href="https://www.pagerduty.com/platform/on-call-management/"&gt;management&lt;/a&gt; with flexible schedules, &lt;a href="https://www.pagerduty.com/platform/modern-incident-response/"&gt;incident&lt;/a&gt; escalation, and alerting.&lt;/li&gt;
&lt;li&gt;Context filtering for alert reduction.&lt;/li&gt;
&lt;li&gt;Automated responses with status updates.&lt;/li&gt;
&lt;li&gt;Event &lt;a href="https://www.pagerduty.com/platform/event-intelligence-and-automation"&gt;automation&lt;/a&gt; with triage, alert grouping, and noise suppression.&lt;/li&gt;
&lt;li&gt;Dashboards for a variety of alert related information like operations, service health, responders, and incidents with customization capabilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A large number of integrations available out of the box, which gives you the possibility to receive notifications on virtually any destination.&lt;/li&gt;
&lt;li&gt;Scheduling and notifications escalation.&lt;/li&gt;
&lt;li&gt;Services prioritization for controlling what is more important.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.pagerduty.com/pricing/"&gt;pricing&lt;/a&gt; is organized around the features and the number of users that will be using PagerDuty with no free tier available. The most basic plan starts from $10 for up to 6 users per month with an additional $15 per user after that and goes up to $47 per user per month depending on the features of the platform you want to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  16. VictorOps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f0KbTZGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g61ay1wktgxz2t2kz1j8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f0KbTZGv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/g61ay1wktgxz2t2kz1j8.jpg" alt="VictorOps"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VictorOps is the tool that will quickly become your central place for alerts and notifications. It makes it possible to take action on alerts, schedule who is on-call and should react to a given incident. With rules-based incident response, it is easy to automate responses for certain alerts to reduce the noise and fatigue generated by notifications coming from various systems hooked up with the rich set of available integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://victorops.com/product/#on-call"&gt;On-call&lt;/a&gt; scheduling and management with incident escalation and hands-off.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://victorops.com/product/#alerts"&gt;Alerts&lt;/a&gt; and notification centralization.&lt;/li&gt;
&lt;li&gt;Incident &lt;a href="https://victorops.com/product/#automation"&gt;automation&lt;/a&gt; with alert rules, automatic response, and noise suppression.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://victorops.com/product/#reports"&gt;Reports&lt;/a&gt; and post-incident reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A large number of integrations available out of the box for centralizing the alerts and notifications in a single place.&lt;/li&gt;
&lt;li&gt;Dedicated tools for teams.&lt;/li&gt;
&lt;li&gt;Scheduling and incident escalation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://victorops.com/pricing"&gt;pricing&lt;/a&gt; is based one features and the number of users. The basic plan starts from $8 per user per month when paid monthly and goes up to $33 per user per month for the Enterprise plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  17. OpsGenie
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4JeBrA6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hdh4sok3c3bembz4ie9f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4JeBrA6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hdh4sok3c3bembz4ie9f.jpg" alt="OpsGenie"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the creators of JIRA and Confluence comes OpsGenie, the central place for your alerts and notifications. It allows for management of alerts, planning on-call schedules, and reacting automatically based on user-defined rules. With a rich set of integrations, heartbeat monitoring, and alerts deduplication the platform can be used as a tool for centralizing all of your alerts and notifications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;On-call &lt;a href="http://atlassian.com/software/opsgenie/on-call-management-and-escalations#on-call-schedule-management"&gt;scheduling&lt;/a&gt; and &lt;a href="http://atlassian.com/software/opsgenie/on-call-management-and-escalations#on-call-schedule-management"&gt;management&lt;/a&gt; with incident escalation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.atlassian.com/software/opsgenie/it-alerting"&gt;Alerts&lt;/a&gt; and notification centralization with rule-based routing.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.atlassian.com/software/opsgenie/advanced-reporting-and-analytics"&gt;Advanced reporting&lt;/a&gt; with post-incident analysis.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.atlassian.com/software/opsgenie/communication-and-collaboration#chatops"&gt;ChatOps&lt;/a&gt; and &lt;a href="https://www.atlassian.com/software/opsgenie/communication-and-collaboration#stakeholder-communications"&gt;stakeholder&lt;/a&gt; communications with a web conference bridge.&lt;/li&gt;
&lt;li&gt;Incident command center.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rich set of integrations available out of the box for centralizing the notifications and alerts in a single place.&lt;/li&gt;
&lt;li&gt;Team centric tools for multiple teams integrations.&lt;/li&gt;
&lt;li&gt;Heartbeat monitoring and alerts deduplication.&lt;/li&gt;
&lt;li&gt;Free tier available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.atlassian.com/software/opsgenie/pricing"&gt;pricing&lt;/a&gt; is based on features and the number of users. It starts with the limited free tier for up to 5 users with basic alerting and on-call management aimed for small teams. The first non-free tier starts with $11 per user per month when billed monthly and goes up to $35 per user per month with monthly billing. The price depends on the set of features of the platform that you will use. For instance, if you are OK with up to 25 international SMS notifications per user per month you will be fine with the basic, non-free plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  18. xMatters
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gakz9HbG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tuybdb0jaq4djw48dopn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gakz9HbG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tuybdb0jaq4djw48dopn.jpg" alt="xMatters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.xmatters.com/product/"&gt;xMatters&lt;/a&gt; is a user-friendly central place for all your alerts and notifications. It allows managing and reacting on incidents from a single place with on-call schedules, incident escalation, and rule-based responses and resolutions. With the incident timeline, you can see how the reaction on the incident was performed and how well the team reacted to the situation giving your organization a tool helping you in improving alerts handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.xmatters.com/features/on-call-management/"&gt;On-call&lt;/a&gt; scheduling and &lt;a href="https://www.xmatters.com/features/on-call-management/"&gt;management&lt;/a&gt; with incident escalation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.xmatters.com/features/workflow-process-automation"&gt;Automatic, rule-based&lt;/a&gt; responses and resolutions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.xmatters.com/features/notifications/"&gt;Stakeholder&lt;/a&gt; communication.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.xmatters.com/features/analytics"&gt;Incident timeline&lt;/a&gt; with team performance calculations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Over 100 integrations are available at the time of writing.&lt;/li&gt;
&lt;li&gt;Easy to learn and user-friendly.&lt;/li&gt;
&lt;li&gt;Free tier available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://www.xmatters.com/pricing"&gt;pricing&lt;/a&gt;, similar to the rest of the competitors like OpsGenie and PagerDuty is organized around features and the number of users. The pricing plans start with a free tier that is available for up to 10 users without any kind of SMS and voice notifications. The first paid plan starts at $16 per user per month and goes up to $59 per user per month making it the most expensive of the tools. Of course, the price depends on the features of the platform you choose to use. For example, if you are OK with up to 50 SMS notifications per user per month you will be fine with the basic, non-free plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Tools Will You Use?
&lt;/h2&gt;

&lt;p&gt;Cloud computing, the public, hybrid, and private cloud environments opened up a world of opportunities. Flexibility, on-demand scaling, ready to use services, and the ease of use that comes with that allow for the next generation of platforms to be built on top of them. However, to leverage all the opportunities you need to deal with a set of challenges. Those require good tools so you can understand the state of the environment along with all the key performance indicators that your environment provides. The available cloud monitoring tools all help you with the gathering of observability data, but they take different approaches, provide different functionalities, and come with different costs. With the wide range of solutions available make sure to try different solutions and choose the one that fits your needs the most. Learn how to choose the best monitoring system for your use case from our &lt;a href="https://sematext.com/blog/monitoring-alerting/"&gt;Guide to monitoring and alerting&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>performance</category>
      <category>logs</category>
      <category>monitoring</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Linux Logging Tutorial: What Are Linux Logs, How to View, Search and Centralize Them</title>
      <dc:creator>Radu Gheorghe</dc:creator>
      <pubDate>Mon, 27 Jul 2020 12:17:37 +0000</pubDate>
      <link>https://dev.to/sematext/linux-logging-tutorial-what-are-linux-logs-how-to-view-search-and-centralize-them-2bi5</link>
      <guid>https://dev.to/sematext/linux-logging-tutorial-what-are-linux-logs-how-to-view-search-and-centralize-them-2bi5</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR note&lt;/strong&gt;: if you want the &lt;code&gt;bzip2 -9&lt;/code&gt; version of this post, scroll down to the very last section for some quick pointers. If you want to learn a bit about Linux system logs, please continue, as we'll talk about all these and more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What are Linux logs&lt;/strong&gt; and who generates them&lt;/li&gt;
&lt;li&gt;  Important &lt;strong&gt;types of Linux logs&lt;/strong&gt; and their typical location&lt;/li&gt;
&lt;li&gt;  How to &lt;strong&gt;read and search logs&lt;/strong&gt;, whether they're written by journald or syslog&lt;/li&gt;
&lt;li&gt;  How to &lt;strong&gt;centralize logs&lt;/strong&gt; of many servers in one location. Spoiler alert: the easiest way is to send all system logs to Sematext Cloud in &lt;strong&gt;three commands&lt;/strong&gt;, so you can build actionable dashboards:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flinux-logging-post-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flinux-logging-post-3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Short Recap: What Are Linux Logs?
&lt;/h2&gt;

&lt;p&gt;Linux logs are pieces of data that Linux writes, related to what the server, kernel, services, and applications running on it are doing, with an associated timestamp. They often come with other structured data, such as a hostname, being a valuable &lt;a href="https://sematext.com/blog/log-analysis/" rel="noopener noreferrer"&gt;analysis&lt;/a&gt; and troubleshooting tool for admins when they encounter performance issues. You can read more about logs and why should you monitor them in our &lt;a href="https://sematext.com/guides/log-management/" rel="noopener noreferrer"&gt;complete guide to log management&lt;/a&gt;. Here's an example of SSH log from &lt;code&gt;/var/log/auth.log&lt;/code&gt; directory:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;May 5 08:57:27 ubuntu-bionic sshd[5544]: pam_unix(sshd:session): session opened for user vagrant by (uid=0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice how the log contains a few fields, like the timestamp, the hostname, the process writing the log and its PID, before the message itself. In Linux, logs come from different sources, mainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://sematext.com/blog/journald-logging-tutorial/" rel="noopener noreferrer"&gt;Systemd journal&lt;/a&gt;. Most Linux distros have &lt;a href="https://systemd.io/" rel="noopener noreferrer"&gt;systemd&lt;/a&gt; to manage services (like SSH above). Systemd catches the output of these services (i.e., logs like the one above) and writes them to the journal. The journal is written in a binary format, so you'll use &lt;a href="https://sematext.com/blog/journald-logging-tutorial#toc-journald-commands-via-journalctl-5" rel="noopener noreferrer"&gt;journalctl&lt;/a&gt; to explore it, like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ journalctl
    ...
    May 05 08:57:27 ubuntu-bionic sshd[5544]: pam_unix(sshd:session): session opened for user vagrant by (uid=0)
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/" rel="noopener noreferrer"&gt;Syslog&lt;/a&gt;. When there's no systemd, processes like SSH can write to a UNIX socket (e.g., &lt;code&gt;/dev/log&lt;/code&gt;) in the &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/#toc-syslog-message-formats-2" rel="noopener noreferrer"&gt;syslog message format&lt;/a&gt;. A &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/#toc-syslog-daemons-0" rel="noopener noreferrer"&gt;syslog daemon&lt;/a&gt; (e.g., &lt;a href="https://www.rsyslog.com/" rel="noopener noreferrer"&gt;rsyslog&lt;/a&gt;) then picks the message, parses it and writes it to various destinations. By default, it writes to files in &lt;code&gt;/var/log&lt;/code&gt;, which is how we got the earlier message from /var/log/auth.log.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;The Linux kernel&lt;/strong&gt; writes its own logs to a ring buffer. Systemd or the syslog daemon can read logs from this buffer, then write to the journal or flat files (typically &lt;code&gt;/var/log/kern.log&lt;/code&gt;). You can also see kernel logs directly via &lt;code&gt;dmesg&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dmesg -T
...
[Tue May 5 08:41:31 2020] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://sematext.com/blog/auditd-logs-auditbeat-elasticsearch-logsene/" rel="noopener noreferrer"&gt;Audit logs&lt;/a&gt;. These are a special case of kernel messages designed for auditing actions such as file access. You'd typically have a service to listen for such security logs, like auditd. By default, &lt;a href="https://sematext.com/blog/auditd-logs-auditbeat-elasticsearch-logsene/#toc-audit-logs-in-linux-a-quick-tutorial-on-using-auditd-1" rel="noopener noreferrer"&gt;auditd&lt;/a&gt; writes audit messages to &lt;code&gt;/var/log/audit/audit.log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Application logs&lt;/strong&gt;. Non-system applications tend to write to /var/log as well. Here are some popular examples:

&lt;ul&gt;
&lt;li&gt;  Apache HTTPD logs are typically written to &lt;code&gt;/var/log/httpd&lt;/code&gt; or &lt;code&gt;/var/log/apache2&lt;/code&gt;. HTTP access logs would be in /var/log/httpd/access.log&lt;/li&gt;
&lt;li&gt;  MySQL logs typically go to &lt;code&gt;/var/log/mysql.log&lt;/code&gt; or /var/log/mysqld.log&lt;/li&gt;
&lt;li&gt;  Older Linux versions would record boot logs via &lt;a href="https://manpages.debian.org/buster/bootlogd/bootlogd.8.en.html" rel="noopener noreferrer"&gt;bootlogd&lt;/a&gt; to &lt;code&gt;/var/log/boot&lt;/code&gt; or &lt;code&gt;/var/log/boot.log&lt;/code&gt;. Systemd now takes care of this: you can view boot-related logs via &lt;code&gt;journalctl -b&lt;/code&gt;. Distros without systemd have a syslog daemon reading from the kernel ring buffer, which normally has all the boot messages. So you can find your boot/reboot logs in &lt;code&gt;/var/log/messages&lt;/code&gt; or /var/log/syslog&lt;/li&gt;
&lt;li&gt;  Last but not least, you may have your own apps using a &lt;a href="https://sematext.com/blog/logging-libraries-vs-log-shippers/" rel="noopener noreferrer"&gt;logging library&lt;/a&gt; to write to a specific file&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;These sources can interact with each other: journald can forward all its messages to syslog. Applications can write to syslog or the journal. It's Linux, where everything is configurable. But for now, we'll focus on the defaults: where can you &lt;strong&gt;typically&lt;/strong&gt; find different types of logs in most modern distributions?&lt;/p&gt;

&lt;h2&gt;
  
  
  Log Files Location: Where Are They Stored?
&lt;/h2&gt;

&lt;p&gt;Typically, you'll find Linux server logs in the &lt;code&gt;/var/log&lt;/code&gt; directory. This is where syslog daemons are normally configured to write. It's also where most applications (e.g., Apache HTTPD) write by default. For Systemd journal, the default location is &lt;code&gt;/var/log/journal&lt;/code&gt;, but you can't view the files directly because they're binary. So how &lt;strong&gt;do&lt;/strong&gt; you view them?&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check Linux Logs
&lt;/h2&gt;

&lt;p&gt;If your Linux distro uses Systemd (and most modern distros do), then all your system logs are in the journal. You can view them with &lt;code&gt;journalctl&lt;/code&gt;, and you can find the most important &lt;a href="https://sematext.com/blog/journald-logging-tutorial/#toc-journald-commands-via-journalctl-5" rel="noopener noreferrer"&gt;journalctl commands here&lt;/a&gt;. If your distribution writes to local files via syslog, you can view them with standard text processing tools, such as &lt;a href="https://linux.die.net/man/1/cat" rel="noopener noreferrer"&gt;cat&lt;/a&gt;, &lt;a href="https://linux.die.net/man/1/less" rel="noopener noreferrer"&gt;less&lt;/a&gt; or &lt;a href="https://linux.die.net/man/1/grep" rel="noopener noreferrer"&gt;grep&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# grep "error" /var/log/syslog | tail
Mar 31 09:48:02 ubuntu-bionic rsyslogd: unexpected GnuTLS error -53 - this could be caused by a broken connection. GnuTLS reports: Error in the push function. [v8.2002.0 try https://www.rsyslog.com/e/2078 ]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using &lt;a href="https://linux.die.net/man/8/auditd" rel="noopener noreferrer"&gt;auditd&lt;/a&gt; to manage audit logs, you can check them in &lt;code&gt;/var/log/audit.log&lt;/code&gt; by default, but you can also search them with &lt;a href="https://sematext.com/blog/auditd-logs-auditbeat-elasticsearch-logsene/#toc-searching-and-analyzing-audit-logs-with-ausearch-and-aureport-5" rel="noopener noreferrer"&gt;ausearch&lt;/a&gt;. That said, you're better off shipping these security logs to a central location, especially if you have multiple servers. For this task, a tool like &lt;a href="https://www.elastic.co/beats/auditbeat" rel="noopener noreferrer"&gt;Auditbeat&lt;/a&gt; might work better than auditd. We wrote a separate &lt;a href="https://sematext.com/blog/auditd-logs-auditbeat-elasticsearch-logsene/" rel="noopener noreferrer"&gt;tutorial on centralizing audit logs with Auditbeat&lt;/a&gt;, but in the next section we'll focus on centralizing Linux system logs in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  Centralizing Linux Logs
&lt;/h2&gt;

&lt;p&gt;System logs can be in two places: systemd's journal or plain text files written by a syslog daemon. Some distributions (e.g., Ubuntu) have both: journald is set up to forward to syslog. This is done by setting &lt;code&gt;ForwardToSyslog=Yes&lt;/code&gt; in &lt;code&gt;journald.conf&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centralizing Logs via Journald
&lt;/h3&gt;

&lt;p&gt;Our recommendation is to use the &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-upload.html" rel="noopener noreferrer"&gt;journal-upload&lt;/a&gt; to &lt;a href="https://sematext.com/blog/log-aggregation/" rel="noopener noreferrer"&gt;centralize logs&lt;/a&gt;, if the distribution has systemd. You can check this by running &lt;code&gt;journalctl&lt;/code&gt; - if the command isn't found, you don't have the journal. As promised earlier, you can &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;centralize your system logs to Sematext Cloud with three commands&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Install journal-upload&lt;/strong&gt;. On Ubuntu, this works via &lt;code&gt;sudo apt-get install systemd-journal-remote&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Configure journal-upload&lt;/strong&gt;. In &lt;code&gt;/etc/systemd/journal-upload.conf&lt;/code&gt;, set &lt;code&gt;URL=&lt;/code&gt;&lt;code&gt;http://logsene-journald-receiver.sematext.com:80/YOUR_LOGS_TOKEN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start journal-upload&lt;/strong&gt; now and on every boot: &lt;code&gt;systemctl enable systemd-journal-upload &amp;amp;&amp;amp; systemctl start systemd-journal-upload&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Alternatively, you can use &lt;a href="https://sematext.com/docs/logagent/input-plugin-journald-upload/" rel="noopener noreferrer"&gt;Logagent's journal-upload input&lt;/a&gt; to gather journal entries from one or more machines, before shipping them to a central location. That central location can be &lt;a href="https://sematext.com/logsene" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;, a local &lt;a href="https://sematext.com/guides/elk-stack/" rel="noopener noreferrer"&gt;ELK stack&lt;/a&gt; or something else: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flinux-logging-post-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F06%2Flinux-logging-post-2.png"&gt;&lt;/a&gt; If you want to learn more about journald and journalctl, as well as the options you have around centralizing the journal, have a look at our &lt;a href="https://sematext.com/blog/journald-logging-tutorial" rel="noopener noreferrer"&gt;complete guide to journald&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Centralizing Logs via syslog
&lt;/h3&gt;

&lt;p&gt;There are a few scenarios in which centralizing Linux logs with syslog might make sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Your Linux distribution doesn't have journald. This means system logs go directly to your &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/#toc-syslog-daemons-0" rel="noopener noreferrer"&gt;syslog daemon&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  You want to &lt;strong&gt;use your syslog daemon to collect and parse application logs&lt;/strong&gt; as well. An example is described in our &lt;a href="https://sematext.com/blog/recipe-apache-logs-rsyslog-parsing-elasticsearch/" rel="noopener noreferrer"&gt;tutorial for Apache logs with rsyslog and Elasticsearch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  You want to &lt;strong&gt;forward journal entries to syslog&lt;/strong&gt; (i.e., by setting &lt;code&gt;ForwardToSyslog=Yes&lt;/code&gt; in &lt;code&gt;journald.conf&lt;/code&gt;), so you can use a &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/#toc-syslog-protocols-6" rel="noopener noreferrer"&gt;syslog protocol&lt;/a&gt; as a transport. However, this approach will lose some of journald's structured data: journald only forwards &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/#toc-syslog-message-formats-2" rel="noopener noreferrer"&gt;syslog-specific fields&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Similar to the above, except that you'd &lt;strong&gt;configure the syslog daemon to read from the journal&lt;/strong&gt; (like &lt;code&gt;journalctl&lt;/code&gt; does). This approach doesn't lose structured data, but is more error prone (e.g., in case of journal corruption) and adds more overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all situations listed above, data will go through your syslog daemon. From there, you can send it to any of the supported destinations. Most Linux distributions come with &lt;a href="https://www.rsyslog.com/" rel="noopener noreferrer"&gt;rsyslog&lt;/a&gt; installed. To forward data to another syslog server via TCP, you can add this line in your &lt;code&gt;/etc/rsyslog.conf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*.* @@logsene-syslog-receiver.sematext.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This particular line will forward data to &lt;a href="https://sematext.com/docs/logs/syslog/" rel="noopener noreferrer"&gt;Sematext Cloud's syslog endpoint&lt;/a&gt;, but you can replace &lt;code&gt;logsene-syslog-receiver.sematext.com&lt;/code&gt; with the host name of your own syslog server. Some syslog daemons can output data to Elasticsearch via HTTP/HTTPS. &lt;a href="https://rsyslog.readthedocs.io/en/latest/configuration/modules/omelasticsearch.html" rel="noopener noreferrer"&gt;rsyslog is one of them&lt;/a&gt; and &lt;a href="https://www.syslog-ng.com/technical-documents/doc/syslog-ng-open-source-edition/3.21/administration-guide/32#TOPIC-1197819" rel="noopener noreferrer"&gt;so is syslog-ng&lt;/a&gt;. For example, if you use rsyslog on Ubuntu, you'll install the Elasticsearch output module first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install rsyslog-elasticsearch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in the configuration file, you need two elements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;A template that formats your syslog messages as JSON&lt;/strong&gt;, for Elasticsearch to consume
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;template(name="LogseneFormat" type="list" option.json="on") {
 constant(value="{")
 constant(value="\\"@timestamp\\":\\"")
 property(name="timereported" dateFormat="rfc3339")
 constant(value="\\",\\"message\\":\\"")
 property(name="msg")
 constant(value="\\",\\"host\\":\\"")
 property(name="hostname")
 constant(value="\\",\\"severity\\":\\"")
 property(name="syslogseverity-text")
 constant(value="\\",\\"facility\\":\\"")
 property(name="syslogfacility-text")
 constant(value="\\",\\"syslog-tag\\":\\"")
 property(name="syslogtag")
 constant(value="\\",\\"source\\":\\"")
 property(name="programname")
 constant(value="\\"}")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;An action that forwards data to Elasticsearch&lt;/strong&gt;, using the template specified above
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module(load="omelasticsearch")
action(type="omelasticsearch"
 template="LogseneFormat" # the template that you defined earlier
 searchIndex="LOGSENE_APP_TOKEN_GOES_HERE"
 server="logsene-receiver.sematext.com"
 serverport="443"
 usehttps="on"
 bulkmode="on"
 queue.dequeuebatchsize="100" # how many messages to send at once
 action.resumeretrycount="-1") # buffer messages if connection fails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above example shows how to send messages to &lt;a href="https://sematext.com/docs/logs/index-events-via-elasticsearch-api/" rel="noopener noreferrer"&gt;Sematext Cloud's Elasticsearch API&lt;/a&gt;, but you can adjust the action element to point it to your local Elasticsearch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;searchIndex&lt;/code&gt; would be your own &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/7.6/indices-rollover-index.html" rel="noopener noreferrer"&gt;rolling index alias&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;server&lt;/code&gt; would be the hostname of an Elasticsearch node&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;serverport&lt;/code&gt; can be 9200 or a custom port Elasticsearch listens to&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;usehttps="off"&lt;/code&gt; would send data over plain HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you use a syslog protocol, the Elasticsearch API or something else, it's better to &lt;strong&gt;forward syslog directly&lt;/strong&gt; from the syslog daemon than to &lt;strong&gt;tail individual files from&lt;/strong&gt; /var/log using a &lt;a href="https://sematext.com/blog/logstash-alternatives/" rel="noopener noreferrer"&gt;different log shipper&lt;/a&gt;. Tailing files will add overhead and miss some of the metadata, such as facility or severity. Which is not to say that files in /var/log are useless. You'll need them in two scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Logs of applications that write directly to /var/log. For example, HTTP logs, FTP logs, mysql logs and so on. You can tail such files with a log shipper. We have tutorials on &lt;a href="https://sematext.com/blog/recipe-apache-logs-rsyslog-parsing-elasticsearch/" rel="noopener noreferrer"&gt;parsing apache logs with rsyslog&lt;/a&gt; and &lt;a href="https://sematext.com/blog/getting-started-with-logstash/" rel="noopener noreferrer"&gt;with Logstash&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Process system logs with UNIX text tools like grep&lt;/strong&gt;. Here, different log files contain different kinds of data. We'll look at the typical configuration in the next section.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Are the Most Important Log Files You Should Monitor
&lt;/h2&gt;

&lt;p&gt;By default, some distributions write system logs to syslog (either directly or from the journal). The syslog daemon writes these logs to files under &lt;code&gt;/var/log&lt;/code&gt;. Typically that syslog daemon is rsyslog, though syslog-ng works in a similar fashion. In this section, we'll look at the important log files and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  what kind of information you'll find in them&lt;/li&gt;
&lt;li&gt;  how is rsyslog configured to write there (in case you want to change the configuration)&lt;/li&gt;
&lt;li&gt;  how to view the same information with &lt;code&gt;journalctl&lt;/code&gt;, in case it doesn't forward to syslog&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  /var/log/syslog or /var/log/messages
&lt;/h3&gt;

&lt;p&gt;This is the “catch-all” of syslog. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# logger "this is a test"
# tail -1 /var/log/syslog
May 7 15:33:11 ubuntu-bionic test-user: this is a test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically, you'll find all messages here (error logs, informational messages, and every other &lt;a href="https://en.wikipedia.org/wiki/Syslog#Severity_level" rel="noopener noreferrer"&gt;severity&lt;/a&gt;), as this line from &lt;code&gt;/etc/rsyslog.conf&lt;/code&gt; suggests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*.* /var/log/syslog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only exception is the &lt;a href="https://www.rsyslog.com/doc/v8-stable/configuration/actions.html#discard-stop" rel="noopener noreferrer"&gt;stop action&lt;/a&gt;. For example, you may find something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:msg,contains,"[UFW " /var/log/ufw.log
&amp;amp; stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In plain English, this block says:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If the &lt;a href="https://www.rsyslog.com/doc/v8-stable/configuration/properties.html#message-properties" rel="noopener noreferrer"&gt;msg property&lt;/a&gt; of this message contains "[UFW "&lt;/li&gt;
&lt;li&gt;  Then write to /var/log/ufw.log (the &lt;a href="https://www.rsyslog.com/doc/v8-stable/configuration/modules/omfile.html" rel="noopener noreferrer"&gt;file output module&lt;/a&gt; is implied)&lt;/li&gt;
&lt;li&gt;  If the action succeeds (&amp;amp;), then don't process this message further (stop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if the &lt;code&gt;/var/log/syslog&lt;/code&gt; action comes later, it won't write UFW messages there. If there's nothing in &lt;code&gt;/var/log/syslog&lt;/code&gt; or &lt;code&gt;/var/log/messages&lt;/code&gt;, you probably have journald set up not to forward to syslog. The same data (and more) can be viewed via &lt;code&gt;journalctl&lt;/code&gt; with no parameters. By default, &lt;code&gt;journalctl&lt;/code&gt; pages data through &lt;code&gt;less&lt;/code&gt;, but if you want to filter through &lt;code&gt;grep&lt;/code&gt; you'll need to disable paging:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl --no-pager | grep "this is a test"
May 07 15:33:11 ubuntu-bionic test-user[7526]: this is a test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /var/log/kern.log or /var/log/dmesg
&lt;/h3&gt;

&lt;p&gt;This is where kernel messages go by default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apr 17 16:47:28 ubuntu-bionic kernel: [ 0.004000] console [tty1] enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's really down to filtering syslog messages by the &lt;code&gt;kern&lt;/code&gt; facility:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kern.* /var/log/kern.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't have syslog (or the file is missing) and you have journald, you can show kernel messages in &lt;code&gt;journalctl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl -k
...
Apr 17 16:47:28 ubuntu-bionic kernel: console [tty1] enabled
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /var/log/auth.log or /var/log/secure
&lt;/h3&gt;

&lt;p&gt;This is where you find authentication messages, generated by services like sshd:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;May 7 15:03:09 ubuntu-bionic sshd[1202]: pam_unix(sshd:session): session closed for user vagrant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is another filter by facility, this time by two values (&lt;code&gt;auth&lt;/code&gt; and &lt;code&gt;authpriv&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auth,authpriv.* /var/log/auth.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do such filters in &lt;code&gt;journalctl&lt;/code&gt; as well, except that you have to provide &lt;a href="https://en.wikipedia.org/wiki/Syslog#Facility" rel="noopener noreferrer"&gt;numeric facility levels&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl SYSLOG_FACILITY=4 SYSLOG_FACILITY=10
...
May 7 15:03:09 ubuntu-bionic sshd[1202]: pam_unix(sshd:session): session closed for user vagrant
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /var/log/cron.log
&lt;/h3&gt;

&lt;p&gt;This is where your &lt;a href="http://man7.org/linux/man-pages/man8/cron.8.html" rel="noopener noreferrer"&gt;cron&lt;/a&gt; messages go (i.e., jobs that run regularly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;May 06 08:19:01 localhost.localdomain anacron[1142]: Job `cron.daily' started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yet another facility filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cron.* /var/log/cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With journalctl, you'd do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl SYSLOG_FACILITY=9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  /var/log/mail.log or /var/log/maillog
&lt;/h3&gt;

&lt;p&gt;Email daemons such as Postfix typically log to syslog in the &lt;code&gt;mail&lt;/code&gt; facility, just like &lt;code&gt;cron&lt;/code&gt; logs to the &lt;code&gt;cron&lt;/code&gt; facility. Then, rsyslog puts these logs in a different file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mail.* /var/log/mail.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using journald, you can still view mail logs with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl SYSLOG_FACILITY=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because journald exposes the &lt;a href="https://linux.die.net/man/3/syslog" rel="noopener noreferrer"&gt;syslog API&lt;/a&gt;, everything that normally goes to syslog ends up in the journal.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR Takeaways
&lt;/h2&gt;

&lt;p&gt;Let's summarize the actionables here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The location and format of your Linux system logs &lt;strong&gt;depends on how your distro is configured&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Most distros have systemd&lt;/strong&gt;. It means all your system &lt;strong&gt;logs live in the journal&lt;/strong&gt;. To view and search it, &lt;strong&gt;use journalctl&lt;/strong&gt;. Use the &lt;a href="https://sematext.com/blog/journald-logging-tutorial" rel="noopener noreferrer"&gt;complete guide to journald&lt;/a&gt; for reference.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Some distros get system logs to syslog&lt;/strong&gt;. Either directly or through the journal. In this case you likely have logs written to various files in &lt;code&gt;/var/log&lt;/code&gt;. Have a look at the section above for details on each important file.&lt;/li&gt;
&lt;li&gt;  Either way, if you manage multiple servers, you'll want to centralize system logs with a &lt;a href="https://sematext.com/blog/best-log-management-tools/" rel="noopener noreferrer"&gt;log management software&lt;/a&gt; such as &lt;a href="https://sematext.com/cloud" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;. Sematext makes this very easy, as it has both &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;journald integration&lt;/a&gt; and &lt;a href="https://sematext.com/docs/logs/syslog/" rel="noopener noreferrer"&gt;syslog integration&lt;/a&gt;. Though you can use your own &lt;a href="https://sematext.com/guides/elk-stack/" rel="noopener noreferrer"&gt;ELK stack&lt;/a&gt; if you prefer &lt;a href="https://sematext.com/elastic-stack-alternative/" rel="noopener noreferrer"&gt;build vs buy&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  If you need help with your own ELK stack, please reach out, as we provide &lt;a href="https://sematext.com/consulting/logging/" rel="noopener noreferrer"&gt;ELK stack consulting&lt;/a&gt;, &lt;a href="https://sematext.com/support/elasticsearch-production-support/" rel="noopener noreferrer"&gt;Elasticsearch production support&lt;/a&gt; and &lt;a href="https://sematext.com/training/elasticsearch/" rel="noopener noreferrer"&gt;Elasticsearch and ELK stack training classes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>linux</category>
      <category>logging</category>
    </item>
    <item>
      <title>Tutorial: Logging with journald</title>
      <dc:creator>Radu Gheorghe</dc:creator>
      <pubDate>Tue, 09 Jun 2020 07:37:39 +0000</pubDate>
      <link>https://dev.to/sematext/tutorial-logging-with-journald-50l8</link>
      <guid>https://dev.to/sematext/tutorial-logging-with-journald-50l8</guid>
      <description>&lt;p&gt;If you're using Linux, I'm sure you bumped into &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html" rel="noopener noreferrer"&gt;journald&lt;/a&gt;: it's what most distros use by default for system logging. Most applications running as a service will also log to the journal. So how do you make use of these logs to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  find the error or debug message that you're looking for?&lt;/li&gt;
&lt;li&gt;  make sure logs don't fill your disk?&lt;/li&gt;
&lt;li&gt;  centralize journals so you don't have to ssh to each box?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we'll answer all the above and more. We will dive into the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;what is journald&lt;/strong&gt;, how it came to be and what are its benefits&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;main configuration options&lt;/strong&gt;, like when to remove old logs so you don't run out of disk&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;journald and containers&lt;/strong&gt;: can/should containers log to the journal?&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;journald vs syslog&lt;/strong&gt;: advantages and disadvantages of both, how they integrate&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ways to centralize journals&lt;/strong&gt;. Advantages and disadvantages of each method, and which is &lt;a href="https://sematext.com/product-updates/%23/2020/we-have-a-new-logs-integration-for-journald" rel="noopener noreferrer"&gt;the best&lt;/a&gt;. Spoiler alert: you can &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;configure journald to send logs directly to Sematext Cloud&lt;/a&gt;; or you can &lt;a href="https://sematext.com/docs/logagent/input-plugin-journald-upload/" rel="noopener noreferrer"&gt;use the open-source Logagent as a journald aggregator&lt;/a&gt;. Either way, you'll have one place to search and analyze your journal events:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F04%2Fjornald-logging-post-image2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F04%2Fjornald-logging-post-image2.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are lots of other options to centralize journal entries, and lots of tools to help. We'll explore them in detail, but before that, let's zoom in to journald itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is journald?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;journald&lt;/strong&gt; is the part of &lt;a href="https://systemd.io/" rel="noopener noreferrer"&gt;systemd&lt;/a&gt; that deals with logging. &lt;strong&gt;systemd&lt;/strong&gt;, at its core, is in charge of managing services: it starts them up and keeps them alive.&lt;/p&gt;

&lt;p&gt;All services and systemd itself need to log: “ssh started” or “user root logged in”, they might say. That's where journald comes in: to capture these logs, record them, make them easy to find, and remove them when they pass a certain age.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use journald?
&lt;/h2&gt;

&lt;p&gt;In short, because syslog sucks :) Jokes aside, the &lt;a href="https://docs.google.com/document/pub?id%3D1IC9yOXj7j6cdLLxWEBAGRL6wl97tFxgjLUEHIX3MSTs%26pli%3D1" rel="noopener noreferrer"&gt;paper announcing journald&lt;/a&gt; explained that systemd needed functionality that was hard to get through &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/" rel="noopener noreferrer"&gt;existing syslog implementations&lt;/a&gt;. Examples include structured logging, indexing logs for fast search, access control and signed messages.&lt;/p&gt;

&lt;p&gt;As you might expect, &lt;a href="https://rainer.gerhards.net/2013/05/rsyslog-vs-systemd-journal.html" rel="noopener noreferrer"&gt;not everyone agrees with these statements&lt;/a&gt; or the general approach systemd took with journald. But by now, systemd is adopted by most Linux distributions, and it includes journald as well. journald happily coexists with syslog daemons, as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  some syslog daemons can both read from and write to the journal&lt;/li&gt;
&lt;li&gt;  journald exposes the &lt;a href="https://linux.die.net/man/3/syslog" rel="noopener noreferrer"&gt;syslog API&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  journald benefits
&lt;/h3&gt;

&lt;p&gt;Think of journald as your mini-command-line-&lt;a href="https://sematext.com/guides/elk-stack/" rel="noopener noreferrer"&gt;ELK&lt;/a&gt; that lives on virtually every Linux box. It provides lots of features, most importantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Indexing&lt;/strong&gt;. journald uses a binary storage for logs, where data is indexed. Lookups are much faster than with plain text files&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Structured logging&lt;/strong&gt;. Though &lt;a href="https://sematext.com/blog/structured-logging-with-rsyslog-and-elasticsearch/" rel="noopener noreferrer"&gt;it's possible with syslog, too&lt;/a&gt;, it's enforced here. Combined with indexing, it means you can easily filter specific logs (e.g. with a set priority, in a set timeframe)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Access control&lt;/strong&gt;. By default, storage files are split by user, with different permissions to each. As a regular user, you won't see everything root sees, but you'll see your own logs&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Automatic log rotation&lt;/strong&gt;. You can configure journald (see below) to keep logs only up to a space limit, or based on free space&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring journald
&lt;/h2&gt;

&lt;p&gt;To tweak how journald behaves, you'll edit &lt;code&gt;/etc/systemd/journald.conf&lt;/code&gt; and then reload the journal service like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl reload systemd-journald.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Though &lt;a href="https://github.com/systemd/systemd/issues/2236" rel="noopener noreferrer"&gt;earlier versions of journald need to be restarted&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl restart systemd-journald.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Most important settings will be around storage: whether the journal should be kept in memory or on disk, when to remove old logs and how much to rate limit. We'll focus on some of those next, but you can see all the configuration options in &lt;a href="https://www.freedesktop.org/software/systemd/man/journald.conf.html%23" rel="noopener noreferrer"&gt;journald.conf's man page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  journald storage
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;Storage&lt;/code&gt;&lt;/strong&gt; option controls whether the journal is stored in memory (under &lt;code&gt;/run/log/journal&lt;/code&gt;) or on disk (under &lt;code&gt;/var/log/journal&lt;/code&gt;). Setting &lt;strong&gt;&lt;code&gt;Storage=volatile&lt;/code&gt;&lt;/strong&gt; will store the journal in memory, while &lt;strong&gt;&lt;code&gt;Storage=persistent&lt;/code&gt;&lt;/strong&gt; will store it on disk. Most distributions have it set to auto, which means it will store the journal on disk if &lt;code&gt;/var/log/journal&lt;/code&gt; exists, otherwise it will be stored in memory.&lt;/p&gt;

&lt;p&gt;Once you've decided where to store the journal, you may want to set some limits. For example, &lt;strong&gt;&lt;code&gt;SystemMaxUse=4G&lt;/code&gt;&lt;/strong&gt; will limit &lt;code&gt;/var/log/journal&lt;/code&gt; to about 4GB. Similarly, &lt;strong&gt;&lt;code&gt;SystemKeepFree=10G&lt;/code&gt;&lt;/strong&gt; will try to keep 10GB of disk space free. If you choose to keep the journal in memory, the equivalent options are &lt;strong&gt;&lt;code&gt;RuntimeMaxUse&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;RuntimeKeepFree&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can check the current disk usage of the journal with &lt;a href="https://www.freedesktop.org/software/systemd/man/journalctl.html" rel="noopener noreferrer"&gt;journalctl&lt;/a&gt; via &lt;strong&gt;&lt;code&gt;journalctl --disk-usage&lt;/code&gt;&lt;/strong&gt;. If you need to, you can clean it up on demand via &lt;strong&gt;&lt;code&gt;journalctl --vacuum-size=4GB&lt;/code&gt;&lt;/strong&gt; (i.e. to reduce it to 4GB).&lt;/p&gt;

&lt;p&gt;Compression is enabled by default on log entries larger than 512 bytes. If you want to change this threshold to, say 1KB, you'd add &lt;strong&gt;&lt;code&gt;Compress=1K&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also by default, journald will drop all log messages from a service if it passes certain limits. These limits can be configured via &lt;strong&gt;&lt;code&gt;RateLimitBurst&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;RateLimitIntervalSec&lt;/code&gt;&lt;/strong&gt;, which default to &lt;strong&gt;&lt;code&gt;10000&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;30s&lt;/code&gt;&lt;/strong&gt; respectively. Actual values will depend on the available free space. For example, if you have more than 64GB of free disk space, the multiplier will be 6. Meaning it will drop logs from a service after 60K messages sent in 30 seconds.&lt;/p&gt;

&lt;p&gt;The rate limit defaults are sensible, unless you have a specific service that's generating lots of logs (e.g. a web server). In that case, it might be better to &lt;strong&gt;&lt;code&gt;LogRateLimitBurst&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;LogRateLimitIntervalSec&lt;/code&gt;&lt;/strong&gt; in that application's &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd.exec.html" rel="noopener noreferrer"&gt;service definition&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  journald commands via journalctl
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/journalctl.html" rel="noopener noreferrer"&gt;journalctl&lt;/a&gt; is your main tool for interacting with the journal. If you just run it, you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  all entries, from oldest to newest&lt;/li&gt;
&lt;li&gt;  paged by &lt;a href="https://linux.die.net/man/1/less" rel="noopener noreferrer"&gt;less&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  lines go past the edge of your screen if they have to (use left and right arrow keys to navigate)&lt;/li&gt;
&lt;li&gt;  format is similar to the syslog output, as it is configured in most Linux distributions: &lt;strong&gt;syslog timestamp + hostname + program and its PID + message&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's an example snippet:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apr 09 10:22:49 localhost.localdomain su[866]: pam_unix(su-l:session): session opened for user solr by (uid=0)&amp;lt;
Apr 09 10:22:49 localhost.localdomain systemd[1]: Started Session c1 of user solr.&amp;lt;
Apr 09 10:22:49 localhost.localdomain systemd[1]: Created slice User Slice of solr.&amp;lt;
Apr 09 10:22:49 localhost.localdomain su[866]: (to solr) root on none
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is rarely what you want. More common scenarios are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;last N lines&lt;/strong&gt; (equivalent of tail -n 20 - if N=20): &lt;code&gt;journalctl -n 20&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;follow&lt;/strong&gt; (tail -f equivalent): &lt;code&gt;journalctl -f&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  page &lt;strong&gt;from newest to oldest&lt;/strong&gt;: &lt;code&gt;journalctl --reverse&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;skip paging and just grep&lt;/strong&gt; for something (e.g. “solr”): &lt;code&gt;journalctl --no-pager | grep solr&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you often find yourself using &lt;code&gt;--no-pager&lt;/code&gt;, you can change the default pager through the &lt;code&gt;SYSTEMD_PAGER&lt;/code&gt; variable. &lt;code&gt;export SYSTEMD_PAGER=cat&lt;/code&gt; &lt;strong&gt;will disable paging&lt;/strong&gt;. That said, you might want to look into journalctl's own options for displaying and filtering - described below - before using text processing tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  journalctl display settings
&lt;/h3&gt;

&lt;p&gt;The main option here is &lt;code&gt;--output&lt;/code&gt;, which can &lt;a href="https://www.freedesktop.org/software/systemd/man/journalctl.html" rel="noopener noreferrer"&gt;take many values&lt;/a&gt;. As an &lt;a href="https://sematext.com/consulting/logging/" rel="noopener noreferrer"&gt;ELK consultant&lt;/a&gt;, I want my timestamps &lt;a href="https://en.wikipedia.org/wiki/ISO_8601" rel="noopener noreferrer"&gt;ISO 8601&lt;/a&gt;, and &lt;strong&gt;&lt;code&gt;--output=short-iso&lt;/code&gt;&lt;/strong&gt; will do just that. Now this is more like it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2020-04-09T10:23:01+0000 localhost.localdomain solr[860]: Started Solr server on port 8983 (pid=999). Happy searching!
2020-04-09T10:23:01+0000 localhost.localdomain su[866]: pam_unix(su-l:session): session closed for user solr
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;journald keeps more information than what the &lt;strong&gt;short/short-iso&lt;/strong&gt; output shows. Adding &lt;strong&gt;&lt;code&gt;--output=json-pretty&lt;/code&gt;&lt;/strong&gt; (or just &lt;strong&gt;json&lt;/strong&gt; if you want it compact) can look like this for a single event:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
 "__CURSOR" : "s=83694dffb084461ea30a168e6cef1e6c;i=103f;b=f0bbba1703cb43229559a8fcb4cb08b9;m=c2c9508c;t=5a2d9c22f07ed;x=c5fe854a514cef39",
 "__REALTIME_TIMESTAMP" : "1586431033018349",
 "__MONOTONIC_TIMESTAMP" : "3267973260",
 "_BOOT_ID" : "f0bbba1703cb43229559a8fcb4cb08b9",
 "PRIORITY" : "6",
 "_UID" : "0",
 "_GID" : "0",
 "_MACHINE_ID" : "13e3a06d01d54447a683822d7e0b4dc9",
 "_HOSTNAME" : "localhost.localdomain",
 "SYSLOG_FACILITY" : "3",
 "SYSLOG_IDENTIFIER" : "systemd",
 "_TRANSPORT" : "journal",
 "_PID" : "1",
 "_COMM" : "systemd",
 "_EXE" : "/usr/lib/systemd/systemd",
 "_CAP_EFFECTIVE" : "1fffffffff",
 "_SYSTEMD_CGROUP" : "/",
 "CODE_FILE" : "src/core/job.c",
 "CODE_FUNCTION" : "job_log_status_message",
 "RESULT" : "done",
 "MESSAGE_ID" : "9d1aaa27d60140bd96365438aad20286",
 "_SELINUX_CONTEXT" : "system_u:system_r:init_t:s0",
 "UNIT" : "user-0.slice",
 "MESSAGE" : "Removed slice User Slice of root.",
 "CODE_LINE" : "781",
 "_CMDLINE" : "/usr/lib/systemd/systemd --switched-root --system --deserialize 22",
 "_SOURCE_REALTIME_TIMESTAMP" : "1586431033018103"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is where you can use structured logging to filter events. Next up, we'll look closer at the most important options for filtering.&lt;/p&gt;

&lt;h3&gt;
  
  
  journald log filtering
&lt;/h3&gt;

&lt;p&gt;You can filter by any field (see the JSON output above) by specifying &lt;strong&gt;&lt;em&gt;key=value arguments&lt;/em&gt;&lt;/strong&gt;, like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl _SYSTEMD_UNIT=sshd.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;There are shortcuts, for example the &lt;strong&gt;&lt;code&gt;_SYSTEMD_UNIT&lt;/code&gt;&lt;/strong&gt; above can be expressed as &lt;strong&gt;&lt;code&gt;-u&lt;/code&gt;&lt;/strong&gt;. The above command is the equivalent of of:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl -u sshd.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Other useful shortcuts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;severity&lt;/strong&gt; (here called &lt;strong&gt;priority&lt;/strong&gt;). &lt;strong&gt;&lt;code&gt;journalctl -p warning&lt;/code&gt;&lt;/strong&gt; will show logs with at least a severity of &lt;strong&gt;&lt;code&gt;warning&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  show only kernel messages: &lt;strong&gt;&lt;code&gt;journalctl --dmesg&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also filter by time, of course. Here, you have multiple options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;--since/--until&lt;/code&gt;&lt;/strong&gt; as a &lt;strong&gt;full timestamp&lt;/strong&gt;. For example: &lt;strong&gt;&lt;code&gt;journalctl --since="2020-04-09 11:30:00"&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;date only&lt;/strong&gt; (00:00:00 is assumed as the time): &lt;strong&gt;&lt;code&gt;journalctl --since=2020-04-09&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;abbreviations: journalctl --since=yesterday --until=now&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general, you have to specify the exact value you're looking for. With the exception of _SYSTEMD_UNIT. Here, patterns also work:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl -u sshd*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Newer versions of systemd also allow a &lt;strong&gt;&lt;code&gt;--grep&lt;/code&gt;&lt;/strong&gt; flag, which allows you to filter the &lt;code&gt;MESSAGE&lt;/code&gt; field by regex. But you can always pipe the journalctl output through grep itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  journald and boots
&lt;/h3&gt;

&lt;p&gt;Besides messages logged by applications, journald remembers significant events, such as system reboots. Here's an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl MESSAGE="Server listening on 0.0.0.0 port 22."
**-- Logs begin at Wed 2020-04-08 11:53:18 UTC, end at Thu 2020-04-09 12:01:01 UTC. --**
Apr 08 11:53:23 localhost.localdomain sshd[822]: Server listening on 0.0.0.0 port 22.
Apr 08 13:23:42 localhost.localdomain sshd[7425]: Server listening on 0.0.0.0 port 22.
**-- Reboot --**
Apr 09 10:22:49 localhost.localdomain sshd[857]: Server listening on 0.0.0.0 port 22.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can suppress these special messages via &lt;strong&gt;-q&lt;/strong&gt;. Use &lt;strong&gt;-b&lt;/strong&gt; to show only messages after a certain boot. For example, to show messages since the last boot:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl MESSAGE="Server listening on 0.0.0.0 port 22." -b
-- Logs begin at Wed 2020-04-08 11:53:18 UTC, end at Thu 2020-04-09 12:01:01 UTC. --
Apr 09 10:22:49 localhost.localdomain sshd[857]: Server listening on 0.0.0.0 port 22.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can specify a boot as an offset to the current one (e.g. &lt;strong&gt;-b -1&lt;/strong&gt; is the boot before the last). You can also specify a boot ID, but to do this you need to know what are the available boot IDs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl --list-boots
-1 d26652f008ef4020b15a3d510bbcb381 Wed 2020-04-08 11:53:18 UTC—Wed 2020-04-08 14:31:16 UTC
 0 f0bbba1703cb43229559a8fcb4cb08b9 Thu 2020-04-09 10:22:43 UTC—Thu 2020-04-09 12:01:01 UTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And then:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl MESSAGE="Server listening on 0.0.0.0 port 22." -b d26652f008ef4020b15a3d510bbcb381
-- Logs begin at Wed 2020-04-08 11:53:18 UTC, end at Thu 2020-04-09 12:01:01 UTC. --
Apr 08 11:53:23 localhost.localdomain sshd[822]: Server listening on 0.0.0.0 port 22.
Apr 08 13:23:42 localhost.localdomain sshd[7425]: Server listening on 0.0.0.0 port 22.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is all useful if you configure journald for persistent storage (see the configuration section above).&lt;/p&gt;

&lt;h2&gt;
  
  
  journald centralized logging
&lt;/h2&gt;

&lt;p&gt;As you probably noticed, journald is quite host-centric. In practice, you'll want to access these logs in a central location, without having to SSH into each machine.&lt;/p&gt;

&lt;p&gt;There are multiple ways of centralizing journald logs, and we'll detail each below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-upload.html" rel="noopener noreferrer"&gt;systemd-journal-upload&lt;/a&gt; uploads journal entries&lt;/strong&gt;. Either &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;directly to Sematext Cloud&lt;/a&gt; or to a log shipper that can read its output, such as the &lt;a href="https://sematext.com/docs/logagent/input-plugin-journald-upload/" rel="noopener noreferrer"&gt;open-source Logagent&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-remote.service.html%23" rel="noopener noreferrer"&gt;systemd-journal-remote&lt;/a&gt; as a “centralizer”&lt;/strong&gt;. The idea is to have all journals on one host, so you can use journalctl to search (see above). This can work in “pull” or “push” mode&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;a &lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/" rel="noopener noreferrer"&gt;syslog daemon&lt;/a&gt; or &lt;a href="https://sematext.com/blog/logstash-alternatives/" rel="noopener noreferrer"&gt;another log shipper&lt;/a&gt; reads from the local journal&lt;/strong&gt;. Then, it forwards logs to a central store like &lt;a href="https://sematext.com/guides/elk-stack/" rel="noopener noreferrer"&gt;ELK&lt;/a&gt; or &lt;a href="https://sematext.com/docs/logs/syslog/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;journald forwards entries to a local syslog socket&lt;/strong&gt;. Then, a log shipper (typically a syslog daemon) picks messages up and forwards them to the central store&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  systemd-journal-upload to ELK or Sematext Cloud
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-upload.html" rel="noopener noreferrer"&gt;systemd-journal-upload&lt;/a&gt; is a service that pushes new journal entries over HTTP/HTTPS. That destination can be the &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;Sematext Cloud Journald Receiver&lt;/a&gt; - the easiest way to centralize journald logs. And probably the best, as we'll discuss below.&lt;/p&gt;

&lt;p&gt;Although it's part of journald/systemd, &lt;code&gt;systemd-journal-upload&lt;/code&gt; isn't installed by default on most distros. So you have to add it via something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt-get install systemd-journal-remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, uploading journal entries is as easy as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemd-journal-upload --url=http://logsene-journald-receiver.sematext.com:80/YOUR_LOGS_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Though most likely you'll want to configure it as a service:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat /etc/systemd/journal-upload.conf
[Upload]
URL=http://logsene-journald-receiver.sematext.com:80/YOUR_LOGS_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you need more control, or if you want to send journal entries to your local Elasticsearch, you can use the &lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;open-source&lt;/a&gt;&lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;Logagent&lt;/a&gt; with its &lt;a href="https://sematext.com/docs/logagent/input-plugin-journald-upload/" rel="noopener noreferrer"&gt;journald input plugin&lt;/a&gt; as a journald centralizer: &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F04%2Fjornald-logging-post-image1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsematext.com%2Fwp-content%2Fuploads%2F2020%2F04%2Fjornald-logging-post-image1.png"&gt;&lt;/a&gt; Here's the relevant part of &lt;code&gt;logagent.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input:
  journal-upload:
    module: input-journald-upload
    port: 9090
    worker: 0
    systemdUnitFilter:
      include: !!js/regexp /.*/i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Using Logagent and Elasticsearch or Sematext Cloud&lt;/strong&gt; (i.e. we host Logagent and Elasticsearch for you) is probably &lt;strong&gt;the best option to centralize journald logs&lt;/strong&gt;. That's because you get all journald's structured data over a reliable protocol (HTTP/HTTPS) with minimal overhead. The catch? Initial import is tricky, because it can generate a massive HTTP payload. For this, you might want to do the initial import by streaming journalctl output through &lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;Logagent&lt;/a&gt;, like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl --output=json --no-page | logagent --index SEMATEXT-LOGS-TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  systemd-journal-remote
&lt;/h3&gt;

&lt;p&gt;Journald comes with its own “log centralizer”: &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-remote.service.html%23" rel="noopener noreferrer"&gt;systemd-journal-remote&lt;/a&gt;. You don't get anywhere near the flexibility of ELK/Sematext Cloud, but it's already there and it might be enough for small environments.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;systemd-journal-remote&lt;/code&gt; can either pull journals from remote systems or listen for journal entries on HTTP/HTTPS. The push model - where &lt;code&gt;systemd-journal-upload&lt;/code&gt; is in charge of pushing logs - is typically better because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  it can continuously tail the journal and remembers where it left off (i.e. maintains a cursor)&lt;/li&gt;
&lt;li&gt;  you don't need to open access to the journal of every system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;systemd-journal-remote&lt;/code&gt; typically comes in the same package as &lt;code&gt;systemd-journal-upload&lt;/code&gt;. Once it's installed, you can make it listen to HTTP/HTTPS traffic:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host2# systemd-journal-remote --listen-http=0.0.0.0:19352 --output=/var/log/journal/remote
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you can push the journal of a remote host like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host1# systemd-journal-upload --url=http://host2:19352
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  systemd-journal-remote and systemd-journal-gatewayd
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-remote.service.html%23" rel="noopener noreferrer"&gt;s&lt;/a&gt;&lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-remote.service.html%23" rel="noopener noreferrer"&gt;ystemd-journal-remote&lt;/a&gt; can also pull journal entries from remote hosts. These hosts would normally serve their journal via &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-journal-gatewayd.service.html%23" rel="noopener noreferrer"&gt;systemd-journal-gatewayd&lt;/a&gt; (which is often provided by the same package). Once you have systemd-journal-gatewayd, you can start it via:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host1# systemctl start systemd-journal-gatewayd.socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can verify if it works like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl host1:19531/entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, from the “central” host, you can use systemd-journal-remote to fetch journal entries:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;host2# systemd-journal-remote --url [http://](http://host1:19531)[host1](http://host1:19531)[:19531](http://host1:19531)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By default, systemd-journal-remote will write the imported journal to &lt;code&gt;/var/log/journal/remote/&lt;/code&gt; (you might have to create it first!), so you can search them via &lt;code&gt;journalctl&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl -D /var/log/journal/remote/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Tools that read directly from the journal
&lt;/h3&gt;

&lt;p&gt;Another approach for centralizing journald logs is to &lt;strong&gt;have a &lt;a href="https://sematext.com/blog/logstash-alternatives/" rel="noopener noreferrer"&gt;log shipper&lt;/a&gt; read from the journal&lt;/strong&gt;, much like journalctl does. Then, it can process logs and send them to destinations like Elasticsearch or Sematext Cloud (which exposes the &lt;a href="https://sematext.com/docs/logs/index-events-via-elasticsearch-api/" rel="noopener noreferrer"&gt;Elasticsearch API&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;For this approach, there's a PoC &lt;a href="https://github.com/logstash-plugins/logstash-input-journald" rel="noopener noreferrer"&gt;journald input plugin for Logstash&lt;/a&gt;. As you probably know, &lt;a href="https://sematext.com/blog/getting-started-with-logstash/" rel="noopener noreferrer"&gt;Logstash is easy to use&lt;/a&gt;, so reading from the journal is as easy as:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input {
  journald {
  # you may add other options here, but of course the defaults are sensible :)
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.elastic.co/guide/en/beats/journalbeat/master/journalbeat-overview.html" rel="noopener noreferrer"&gt;Journalbeat&lt;/a&gt; is also available. It's as easy to install and use as &lt;a href="https://sematext.com/blog/using-filebeat-to-send-elasticsearch-logs-to-logsene/" rel="noopener noreferrer"&gt;Filebeat&lt;/a&gt;, except that it reads from the journal. But it's marked as experimental.&lt;/p&gt;

&lt;p&gt;Why PoC and experimental? Because of potential journal corruption which might lead to nasty results. Check the comments in &lt;a href="https://www.rsyslog.com/doc/v8-stable/configuration/modules/imjournal.html" rel="noopener noreferrer"&gt;rsyslog's journal input documentation&lt;/a&gt; for details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sematext.com/blog/what-is-syslog-daemons-message-formats-and-protocols/" rel="noopener noreferrer"&gt;Syslog daemons&lt;/a&gt; are also log shippers. Some of them can also read from the journal, or even write to it. There's a lot to say about syslog and the journal, so we'll dissect the topic in a section of its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  journald vs syslog
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Journald provides a good out-of-the-box logging experience&lt;/strong&gt; for systemd. The trade-off is, journald is &lt;strong&gt;a bit of a monolith&lt;/strong&gt;, having everything from log storage and rotation, to log transport and search. Some would argue that &lt;strong&gt;syslog is more UNIX-y&lt;/strong&gt;: more lenient, easier to integrate with other tools. Which was its main criticism to begin with.&lt;/p&gt;

&lt;p&gt;Flame wars aside, there's good integration between the two. Journald provides a &lt;a href="https://manpages.debian.org/jessie/manpages-dev/syslog.3.en.html" rel="noopener noreferrer"&gt;syslog API&lt;/a&gt; and can forward to syslog (see below). On the other hand, syslog daemons have journal integrations. For example, &lt;a href="https://www.rsyslog.com/" rel="noopener noreferrer"&gt;rsyslog&lt;/a&gt; provides plugins to both &lt;a href="https://www.rsyslog.com/doc/v8-stable/configuration/modules/imjournal.html" rel="noopener noreferrer"&gt;read from journald&lt;/a&gt; and &lt;a href="https://rsyslog.readthedocs.io/en/latest/configuration/modules/omjournal.html" rel="noopener noreferrer"&gt;write to journald&lt;/a&gt;. In fact, they recommend two architectures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A small setup (e.g. N embedded devices and one server) could work by centralizing journald logs (see above). If embedded devices don't have systemd/journald but have syslog, they can centralize via syslog to the server and finally write to the server's journal. This journal will act like a mini-ELK&lt;/li&gt;
&lt;li&gt;  A larger setup can work by aggregating journal entries through a syslog daemon. We'll concentrate on this scenario in the rest of this section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are two ways of centralizing journal entries via syslog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;syslog daemon acts as a journald client&lt;/strong&gt; (like journalctl or Logstash or Journalbeat)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;journald forwards messages to syslog&lt;/strong&gt; (via socket)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Option 1) is slower - reading from the journal is slower than reading from the socket - but captures all the fields from the journal. Option 2) is safer (e.g. no issues with journal corruption), but the journal will only forward traditional syslog fields (like severity, hostname, message..). Typically, you'd go for 2) unless you need the structured info. Here's an example configuration for implementing 1) with rsyslog, and writing all messages to Elasticsearch or &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# module that reads from journal
module(load="imjournal"
 StateFile="/var/run/journal.state" # we write here where we left off
 PersistStateInterval="100" # update the state file every 100 messages
)
# journal entries are read as JSON, we'll need this to parse them
module(load="mmjsonparse")
# Elasticsearch or Sematext Cloud HTTP output
module(load="omelasticsearch")

# this is done on every message (i.e. parses the JSON)
action(type="mmjsonparse")

# output template that simply writes the parsed JSON
template(name="all-json" type="list"){
 property(name="$!all-json")
}

action(type="omelasticsearch"
 template="all-json" # use the template defined earlier
 searchIndex="SEMATEXT-LOGS-APP-TOKEN-GOES-HERE"
 server="logsene-receiver.sematext.com"
 serverport="80"
 bulkmode="on" # use the bulk API
 action.resumeretrycount="-1" # retry indefinitely if Logsene/Elasticsearch is unreachable
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For option 2), we'll need to configure journald to forward to a socket. It's as easy as adding this to /etc/systemd/journald.conf:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ForwardToSyslog=yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And it will write messages, in syslog format, to /run/systemd/journal/syslog. On the rsyslog side, you'll have to configure its &lt;a href="https://rsyslog-doc.readthedocs.io/en/latest/configuration/modules/imuxsock.html" rel="noopener noreferrer"&gt;socket input module&lt;/a&gt; to listen to that socket. Here's a similar example of sending logs to Elasticsearch or Sematext Cloud:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module(load="imuxsock"
 SysSock.Name="/run/systemd/journal/syslog")

# template to write traditional syslog fields as JSON
template(name="plain-syslog"
 type="list") {
 constant(value="{")
 constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
 constant(value="\",\"host\":\"") property(name="hostname")
 constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
 constant(value="\",\"facility\":\"") property(name="syslogfacility-text")
 constant(value="\",\"tag\":\"") property(name="syslogtag" format="json")
 constant(value="\",\"message\":\"") property(name="msg" format="json")
 constant(value="\"}")
}

action(type="omelasticsearch"
 template="plain-syslog" # use the template defined earlier
 searchIndex="SEMATEXT-LOGS-APP-TOKEN-GOES-HERE"
 server="logsene-receiver.sematext.com"
 serverport="80"
 bulkmode="on" # use the bulk API
 action.resumeretrycount="-1" # retry indefinitely if Logsene/Elasticsearch is unreachable
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Whether you read the journal through syslog, systemd-journal-upload or through a log shipper, all the above methods assume that you're dealing with Linux running on bare metal or VMs. But what if you're using containers? Let's explore your options in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  journald and containers
&lt;/h2&gt;

&lt;p&gt;In this context, I think it's worth making a distinction between Docker containers and systemd containers. Let's take them one at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  journald and Docker
&lt;/h3&gt;

&lt;p&gt;Typically, a Docker container won't have systemd, because it would make it too “heavy”. As a consequence, it won't have journald, either. That said, you probably have journald on the host, if the host is running Linux. This means you can use the &lt;a href="https://docs.docker.com/config/containers/logging/journald/" rel="noopener noreferrer"&gt;journald logging driver&lt;/a&gt; to send all the logs of a host's containers to that host's journal. It's as easy as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run my_container --log-driver=journald
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And that container's logs will be in the journal:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# journalctl CONTAINER_NAME=my_container --all
Apr 09 13:03:28 localhost.localdomain dockerd-current[25558]: hello journal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you want to use journald by default, you can make the change in daemon.json and restart Docker:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# cat /etc/docker/daemon.json
{
 "log-driver": "journald"
}
systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you have more than one host, you're back to the centralizing problem that we explored in the previous section: getting all journals in one place. This makes journald an intermediate step that may not be necessary.&lt;/p&gt;

&lt;p&gt;A better approach is to &lt;a href="https://sematext.com/docs/logs/sending-docker-logs/" rel="noopener noreferrer"&gt;centralize container logs&lt;/a&gt; via Logagent, which can run as a container. Here, Logagent picks up logs and forwards them to a central place, like Elasticsearch or Sematext Cloud. But it's not the only way. In fact, we explore different approaches, with their pros and cons, in our &lt;a href="https://sematext.com/guides/docker-logs/" rel="noopener noreferrer"&gt;Complete Guide to Docker logging&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  journald and systemd containers
&lt;/h3&gt;

&lt;p&gt;systemd provides containers as well (called &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-machined.service.html%23" rel="noopener noreferrer"&gt;machines&lt;/a&gt;) via &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html%23" rel="noopener noreferrer"&gt;systemd-nspawn&lt;/a&gt;. Unlike Docker containers, systemd-nspawn machines can log to the journal directly. You can read the logs of a specific machine like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;journalctl --machine $MACHINE_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Where &lt;code&gt;$MACHINE_NAME&lt;/code&gt; is one of the running machines. You'd use &lt;strong&gt;machinectl list&lt;/strong&gt; to see all of them.&lt;/p&gt;

&lt;p&gt;As with Docker's journald logging driver, this setup might be challenging when you have multiple hosts. You'll either want to centralize your journals - as described in the previous section. Or, you can send logs from your systemd containers directly to the central location - either via a &lt;a href="https://sematext.com/blog/logging-libraries-vs-log-shippers/" rel="noopener noreferrer"&gt;log shipper or a logging library&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Did you read all the way to the end? You're a hero! And you probably figured that journald is good for structured logging, quick local searches, and tight integration with systemd. Its design shows its weaknesses when it comes to centralizing log events. Here we have many options, but none is perfect. That said, &lt;a href="https://sematext.com/docs/logagent/input-plugin-journald-upload/" rel="noopener noreferrer"&gt;Logagent's journald input&lt;/a&gt; and &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;Sematext Cloud's journald receiver&lt;/a&gt; (the hosted equivalent) come pretty close.&lt;/p&gt;

</description>
      <category>journald</category>
      <category>journalctl</category>
      <category>syslog</category>
      <category>elk</category>
    </item>
    <item>
      <title>Working with Solr Plugins System</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Mon, 08 Jun 2020 14:03:36 +0000</pubDate>
      <link>https://dev.to/sematext/working-with-solr-plugins-system-4c0d</link>
      <guid>https://dev.to/sematext/working-with-solr-plugins-system-4c0d</guid>
      <description>&lt;p&gt;&lt;a href="https://sematext.com/guides/solr/" rel="noopener noreferrer"&gt;Apache Solr&lt;/a&gt; was always ready to be extended. What was only needed is a binary with the code and the modification of the Solr configuration file, the &lt;strong&gt;solrconfig.xml&lt;/strong&gt; and we were ready. It was even simpler with the Solr APIs that allowed us to create various configuration elements – for example, request handlers. What’s more, the default Solr distribution came with a few plugins already – for example, the Data Import Handler or Learning to Rank.&lt;/p&gt;

&lt;p&gt;As consultants working with clients across different industries, dealing with a wide variety of use cases with Solr clusters monitored by &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt; the next thing that we saw the need for were plugins. Installing those plugins was not hard – put a jar file in a defined place, modify the configuration, reload the core/collection or restart Solr and we are ready. Well not so fast. What if you had hundreds of Solr nodes and you needed to upgrade the plugin or even install it. Yes, that’s where things can get nasty and require automation. Solr was not very supportive in this until one of the recent releases. All of the users that wanted to extend Solr were doing the same thing – manual jar loading. We did the same thing with our plugins – like the &lt;a href="https://github.com/sematext/solr-researcher" rel="noopener noreferrer"&gt;Researcher&lt;/a&gt; or &lt;a href="https://github.com/sematext/query-segmenter" rel="noopener noreferrer"&gt;Query Segmenter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the release of Solr 8.4.0, we’ve got a new functionality that helps us with extending Solr – the plugin management. It allows installing plugins from remote locations and it makes it very easy to do so for us as users. Today I wanted to show you not only how to install Solr plugins using this new feature, but also how to prepare your own plugin repository. Let’s get started.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0dzjsfdir0i7dh6t6uqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0dzjsfdir0i7dh6t6uqr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solr Plugin Management
&lt;/h2&gt;

&lt;p&gt;With Solr 8.4.0, we didn’t only get the script itself but also the whole set of changes under the hood. Those changes include things like package management APIs and scripts, class loader isolation, artifact read and write API and more.&lt;/p&gt;

&lt;p&gt;Let’s start from the beginning though. By default Solr comes with the package loading turned off. One of the reasons for such a decision is security. Users could potentially force Solr to download malicious content, so you need to be sure that your environment is secure and you need to know potential downsides and risks of using that feature. But if we are sure that we want to run Solr with plugin management mechanism turned on we need to add the &lt;strong&gt;enable.packages&lt;/strong&gt; property to Solr startup parameters and set it to &lt;strong&gt;true&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/solr start &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;-Denable&lt;/span&gt;.packages&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start playing around with the packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package Management Basics
&lt;/h2&gt;

&lt;p&gt;Let’s try using the bin/solr script and see what it allows us to do when it comes to package management. The simplest way to check that is just by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;bin/
&lt;span class="nv"&gt;$ &lt;/span&gt;./solr package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the result we will get the following response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Found 1 Solr nodes:

Solr process 20949 running on port 8983
Package Manager

./solr package add-repo
Add a repository to Solr.

./solr package &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;:]
Install a package into Solr. This copies over the artifacts from the repository into Solr&lt;span class="s1"&gt;'s internal package store and sets up classloader for this package to be used.

./solr package deploy [:] [-y] [--update] -collections &amp;lt;package-name&amp;gt;[:] [-y] [--update] -collections  [-p param1=value1 -p param2=value2 …
Bootstraps a previously installed package into the specified collections. It the package accepts parameters for its setup commands, they can be specified (as per package documentation).

./solr package list-installed
Print a list of packages installed in Solr.

./solr package list-available
Print a list of packages available in the repositories.

./solr package list-deployed -c
Print a list of packages deployed on a given collection.

./solr package list-deployed
Print a list of collections on which a given package has been deployed.

./solr package undeploy  -collections
Undeploys a package from specified collection(s)

Note: (a) Please add '&lt;/span&gt;&lt;span class="nt"&gt;-solrUrl&lt;/span&gt; http://host:port&lt;span class="s1"&gt;' parameter if needed (usually on Windows).
      (b) Please make sure that all Solr nodes are started with '&lt;/span&gt;&lt;span class="nt"&gt;-Denable&lt;/span&gt;.packages&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="s1"&gt;' parameter.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems we get everything that is needed. We can add repositories, we can list installed packages, we can install packages, we can deploy packages, list deployed ones and of course undeploy the ones that we no longer need.&lt;/p&gt;

&lt;p&gt;At the time of writing this blog post, there were no Solr plugin repositories publicly available. But for us this is not bad – we can use that to learn even more. We just need to start by preparing our own plugin repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the Package Repository
&lt;/h2&gt;

&lt;p&gt;If you are using a repository that was already created, where the plugins are available you can skip this part of the blog post. But if you would like to learn how to set up a Solr plugin repository on your own, I’ll try to guide you through that process.&lt;/p&gt;

&lt;p&gt;So there are a few steps that need to be taken:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to create a private key that will be used to sign your binaries&lt;/li&gt;
&lt;li&gt;You need to create a public key that Solr will use to verify the signed packages&lt;/li&gt;
&lt;li&gt;You need to create a repository description file that Solr will read when requesting packages from the repository&lt;/li&gt;
&lt;li&gt;And of course, you need to have the binaries that you would like to expose as plugins. We will not be discussing this step though and I will assume you already have that. We created a very naive and simple code at &lt;a href="https://github.com/sematext/example-solr-module" rel="noopener noreferrer"&gt;https://github.com/sematext/example-solr-module&lt;/a&gt;. Have a look if you want.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkeiz7jp9hm1k128nf8n2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkeiz7jp9hm1k128nf8n2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Private and a Public Key
&lt;/h3&gt;

&lt;p&gt;We will start by creating a &lt;strong&gt;private key&lt;/strong&gt;. This key will be used to generate a signature of the binaries that we will be exposing as plugins. For that we will use &lt;strong&gt;openssl&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl genrsa &lt;span class="nt"&gt;-out&lt;/span&gt; sematext_example.pem 512
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command creates a 512 bits RSA key called &lt;strong&gt;sematext_example.pem&lt;/strong&gt;. With that generated, we can now create a public key that will be based on the above key.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;public key&lt;/strong&gt; will be created from the private one and Solr will use it to verify the signatures of the files. The idea is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The package maintainer creates a signature of the package file using the &lt;strong&gt;private key&lt;/strong&gt; and writes the signature in the repository description file,&lt;/li&gt;
&lt;li&gt;During package deployment, the package signature is verified by Solr using the &lt;strong&gt;public key&lt;/strong&gt;. If the signature doesn’t match – the package will not be deployed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create a public key we will again use the &lt;strong&gt;openssl&lt;/strong&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl rsa &lt;span class="nt"&gt;-in&lt;/span&gt; sematext_example.pem &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-outform&lt;/span&gt; DER &lt;span class="nt"&gt;-out&lt;/span&gt; publickey.der 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of the above command is a &lt;strong&gt;publickey.der&lt;/strong&gt; file that we will upload to our repository location along with the binary file and the repository description file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating Package Signature
&lt;/h3&gt;

&lt;p&gt;The last step is generating the signature of the file. We will once again use the &lt;strong&gt;openssl&lt;/strong&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;openssl dgst &lt;span class="nt"&gt;-sha1&lt;/span&gt; &lt;span class="nt"&gt;-sign&lt;/span&gt; sematext.pem solr-example-module-1.0.jar | openssl enc &lt;span class="nt"&gt;-base64&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\\&lt;/span&gt;n | &lt;span class="nb"&gt;sed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result we will have the signature, which in our case looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iXyDDhYkYZgBrYCTxawAdeIJFYR+KHglK4m6uLSR1lo9pFm67dKfIzTmXPHasFVgLwVRbYvGMJG5p69TowMPAg==
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note it somewhere as we will need it soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repository Description
&lt;/h2&gt;

&lt;p&gt;Now that we already have our binary file, the private and the public keys we can create the repository description file that Solr will be looking for inside the repository. This repository has to be called repository.json and needs to include a list of plugins that are available in our repository. Each plugin is defined by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A name,&lt;/li&gt;
&lt;li&gt;A description,&lt;/li&gt;
&lt;li&gt;An array of versions, that include:&lt;/li&gt;
&lt;li&gt;Version itself,&lt;/li&gt;
&lt;li&gt;Release date of the given plugin version,&lt;/li&gt;
&lt;li&gt;An array of artifacts for the version – the URL of the file and the signature that we generated earlier,&lt;/li&gt;
&lt;li&gt;The manifest which includes supported Solr versions, default parameters, setup, uninstall and verification commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;repository.json&lt;/strong&gt; file that we are using for the purpose of this blog post looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"sematext-example"&lt;/span&gt;, &lt;span class="s2"&gt;"description"&lt;/span&gt;: &lt;span class="s2"&gt;"Example plugin created for blog post"&lt;/span&gt;, &lt;span class="s2"&gt;"versions"&lt;/span&gt;: &lt;span class="o"&gt;[{&lt;/span&gt;
    &lt;span class="s2"&gt;"date"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-04-16"&lt;/span&gt;, &lt;span class="s2"&gt;"artifacts"&lt;/span&gt;: &lt;span class="o"&gt;[{&lt;/span&gt;
            &lt;span class="s2"&gt;"url"&lt;/span&gt;: &lt;span class="s2"&gt;"solr-example-module-1.0.jar"&lt;/span&gt;,
            &lt;span class="s2"&gt;"sig"&lt;/span&gt;: &lt;span class="s2"&gt;"iXyDDhYkYZgBrYCTxawAdeIJFYR+KHglK4m6uLSR1lo9pFm67dKfIzTmXPHasFVgLwVRbYvGMJG5p69TowMPAg=="&lt;/span&gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;]&lt;/span&gt;,
        &lt;span class="s2"&gt;"manifest"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"version-constraint"&lt;/span&gt;: &lt;span class="s2"&gt;"8 - 9"&lt;/span&gt;,
          &lt;span class="s2"&gt;"plugins"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
            &lt;span class="o"&gt;{&lt;/span&gt;
              &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"request-handler"&lt;/span&gt;,
              &lt;span class="s2"&gt;"setup-command"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/api/collections/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;collection&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config"&lt;/span&gt;,
                &lt;span class="s2"&gt;"payload"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"add-requesthandler"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RH&lt;/span&gt;&lt;span class="p"&gt;-HANDLER-PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;, &lt;span class="s2"&gt;"class"&lt;/span&gt;:
        &lt;span class="s2"&gt;"sematext-example:com.sematext.blog.solr.ExampleRequestHandler"&lt;/span&gt;&lt;span class="o"&gt;}}&lt;/span&gt;,
                &lt;span class="s2"&gt;"method"&lt;/span&gt;: &lt;span class="s2"&gt;"POST"&lt;/span&gt;
              &lt;span class="o"&gt;}&lt;/span&gt;,
              &lt;span class="s2"&gt;"uninstall-command"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/api/collections/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;collection&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config"&lt;/span&gt;,
                &lt;span class="s2"&gt;"payload"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"delete-requesthandler"&lt;/span&gt;: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RH&lt;/span&gt;&lt;span class="p"&gt;-HANDLER-PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;,
                &lt;span class="s2"&gt;"method"&lt;/span&gt;: &lt;span class="s2"&gt;"POST"&lt;/span&gt;
              &lt;span class="o"&gt;}&lt;/span&gt;,
              &lt;span class="s2"&gt;"verify-command"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"path"&lt;/span&gt;: &lt;span class="s2"&gt;"/api/collections/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;collection&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/config/requestHandler?componentName=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RH&lt;/span&gt;&lt;span class="p"&gt;-HANDLER-PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;meta=true"&lt;/span&gt;,
                &lt;span class="s2"&gt;"method"&lt;/span&gt;: &lt;span class="s2"&gt;"GET"&lt;/span&gt;,
                &lt;span class="s2"&gt;"condition"&lt;/span&gt;:
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$[&lt;/span&gt;&lt;span class="s2"&gt;'config'].['requestHandler'].['&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RH&lt;/span&gt;&lt;span class="p"&gt;-HANDLER-PATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'].['_packageinfo_'].['version']"&lt;/span&gt;,
                &lt;span class="s2"&gt;"expected"&lt;/span&gt;: &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;package&lt;/span&gt;&lt;span class="p"&gt;-version&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
              &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;]&lt;/span&gt;,
          &lt;span class="s2"&gt;"parameter-defaults"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"RH-HANDLER-PATH"&lt;/span&gt;: &lt;span class="s2"&gt;"/sematextexample"&lt;/span&gt;
          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While most of the properties are self-descriptive you should put attention to one thing – the class of the request handler in the setup-command definition. Because of the out-of-the-box class loaders isolation, we need to provide a prefix with the name of the plugin to be able to create the request handler. If we won’t do that Solr will fail to create the request handler, because our class that implements the request handler will not be visible. Keep that in mind when creating the repository description file for your own plugins.&lt;/p&gt;

&lt;p&gt;With all that we can upload it to some remote location like we did with &lt;a href="http://pub-repo.sematext.com/training/solr/blog/repo/" rel="noopener noreferrer"&gt;http://pub-repo.sematext.com/training/solr/blog/repo/&lt;/a&gt; and start using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a New Package Repository
&lt;/h2&gt;

&lt;p&gt;Once we are ready with setting up our own repository or we already have a repository that we would like to install plugins from we can add that repository to Solr. Just remember, to successfully add the repository it needs to provide the &lt;strong&gt;repository.json&lt;/strong&gt; file. The second thing is security – you should avoid adding repositories that don’t use SSL. Adding a repository that doesn’t use a secure connection exposes you and your Solr for &lt;strong&gt;man in the middle&lt;/strong&gt; attacks. The potential thing that can happen is that during the download of the package it can be replaced with a malicious version. Keeping your Solr secure is as important as keeping an eye on the Solr metrics by using one of the Solr monitoring tools like &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we know about the potential security issue let’s use a secure location of the example Solr repository. We do that by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./solr package add-repo sematext https://pub-repo.sematext.com/training/solr/blog/repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using new functionalities of the &lt;strong&gt;bin/solr&lt;/strong&gt; script – the &lt;strong&gt;package&lt;/strong&gt; one. We use one of the possible options, the &lt;strong&gt;add-repo&lt;/strong&gt; which requires us to provide a name and the location. The name in our case is &lt;strong&gt;sematext&lt;/strong&gt; and the location is the last provided parameter.&lt;/p&gt;

&lt;p&gt;If the operation was successful Solr will give us information about the number of nodes found in the cluster, the process identifier and the port on which the instance is running. And finally, the last information that tells that the repository was added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Found 1 Solr nodes:

Solr process 65854 running on port 8983
Added repository: sematext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a side note – I’ll omit the information about the number of nodes, process identifier and the Solr port from the other examples. It should be easier to see the crucial information returned by Solr.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing and Removing Solr Packages
&lt;/h2&gt;

&lt;p&gt;Once the repository is added we can start using it. The first thing that you would usually do is listing the available packages and look for something that we can install to extend our Solr. To list all the available packages we should run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/solr package list-available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response to the above command should be similar to the following one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Available packages:
&lt;span class="nt"&gt;-----&lt;/span&gt;
sematext-example    Example plugin created &lt;span class="k"&gt;for &lt;/span&gt;blog post
  Version: 1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the response, we have a list of packages – each described with a name, description and version. Just as they were defined in the &lt;strong&gt;repository.json&lt;/strong&gt; file. We are very close to being ready for installation. But there is one more thing – the public key that Solr will use to verify the package signature. Where to look for such a key? It will be provided to you or you can download it from the repository itself under the &lt;strong&gt;publickey.der&lt;/strong&gt; name. I’ll do the latter and will download the key by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; publickey.der &lt;span class="nt"&gt;-LO&lt;/span&gt; http://pub-repo.sematext.com/training/solr/blog/repo/publickey.der
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we will have the key we can add it to Solr by using the &lt;strong&gt;bin/solr&lt;/strong&gt; script its &lt;strong&gt;package&lt;/strong&gt; part of the functionality and the &lt;strong&gt;add-key&lt;/strong&gt; action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./solr package add-key publickey.der
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After all those steps we can finally start installing the packages. For example, let’s install the one package that we have available in our sample repository. We do that by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./solr package &lt;span class="nb"&gt;install &lt;/span&gt;sematext-example:1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response that I got from Solr was as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Posting manifest...
Posting artifacts...
Executing Package API to register this package...
Response: &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"responseHeader"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"status"&lt;/span&gt;:0,
    &lt;span class="s2"&gt;"QTime"&lt;/span&gt;:68&lt;span class="o"&gt;}}&lt;/span&gt;
sematext-example installed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that our package is now ready to be used. Let’s create a collection where we can use the package by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./solr create_collection &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By now we should have the package installed and a sample collection created. This means that we are finally ready to use that plugin. To do that we need to deploy it. We can do that to a single collection or multiple ones at the same time. For the purpose of this blog post I will use our &lt;strong&gt;test&lt;/strong&gt; collection and will deploy our plugin by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./solr package deploy sematext-example:1.0.0 &lt;span class="nt"&gt;-collections&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the name of the collection or collections that our plugin should be installed to, we need to provide the name of the plugin and its version. The response was as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Executing &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"add-requesthandler"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;:&lt;span class="s2"&gt;"/sematextexample"&lt;/span&gt;,&lt;span class="s2"&gt;"class"&lt;/span&gt;:&lt;span class="s2"&gt;"sematext-example:com.sematext.blog.solr.ExampleRequestHandler"&lt;/span&gt;&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;path:/api/collections/test/config
Execute this &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;y/n&lt;span class="o"&gt;)&lt;/span&gt;:
y
Executing http://localhost:8983/api/collections/test/config/requestHandler?componentName&lt;span class="o"&gt;=&lt;/span&gt;/sematextexample&amp;amp;meta&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;collection:test
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"responseHeader"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"status"&lt;/span&gt;:0,
    &lt;span class="s2"&gt;"QTime"&lt;/span&gt;:1&lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="s2"&gt;"config"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"requestHandler"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"/sematextexample"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"name"&lt;/span&gt;:&lt;span class="s2"&gt;"/sematextexample"&lt;/span&gt;,
        &lt;span class="s2"&gt;"class"&lt;/span&gt;:&lt;span class="s2"&gt;"sematext-example:com.sematext.blog.solr.ExampleRequestHandler"&lt;/span&gt;,
        &lt;span class="s2"&gt;"_packageinfo_"&lt;/span&gt;:&lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="s2"&gt;"package"&lt;/span&gt;:&lt;span class="s2"&gt;"sematext-example"&lt;/span&gt;,
          &lt;span class="s2"&gt;"version"&lt;/span&gt;:&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;,
          &lt;span class="s2"&gt;"files"&lt;/span&gt;:[&lt;span class="s2"&gt;"/package/sematext-example/1.0.0/solr-example-module-1.0.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
          &lt;span class="s2"&gt;"manifest"&lt;/span&gt;:&lt;span class="s2"&gt;"/package/sematext-example/1.0.0/manifest.json"&lt;/span&gt;,
          &lt;span class="s2"&gt;"manifestSHA512"&lt;/span&gt;:&lt;span class="s2"&gt;"da463cdad3efbe4c9159b29156bbaf26f4aa35a083a8b74fd57e1dfa1f79ee7eaadfd3863f5d88fa2550281c027e82b516ebc64a7fa4159089f32c565813c574"&lt;/span&gt;&lt;span class="o"&gt;}}}}}&lt;/span&gt;

Actual: 1.0.0, expected: 1.0.0
Deployed on &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; and verified package: sematext-example, version: 1.0.0
Deployment successful
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the execution of the above command, the &lt;strong&gt;bin/solr&lt;/strong&gt; script will ask you if you are certain that you would like to deploy the chosen package. If you agree to that Solr will deploy and try to verify the package by using the verification command provided in the &lt;strong&gt;repository.json&lt;/strong&gt; description file. If that went well – the plugin is ready and we can use it.&lt;/p&gt;

&lt;p&gt;When we no longer need a package we can remove it by running the &lt;strong&gt;undeploy&lt;/strong&gt; command. For example, if we would like to remove the previously deployed package we just need to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bin/solr package undeploy sematext-example &lt;span class="nt"&gt;-collections&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the response says that everything went well and we will no longer be using the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Executing &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"delete-requesthandler"&lt;/span&gt;:&lt;span class="s2"&gt;"/sematextexample"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;path:/api/collections/test/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Solr Packages Work Under the Hood
&lt;/h2&gt;

&lt;p&gt;The heart of the implementation of the plugin mechanism is related to the isolation of classloaders of the plugins and the core Solr classes. The plugin mechanism assumes that any change in the files that are in the Solr &lt;strong&gt;classpath&lt;/strong&gt; requires a restart. The rest of the files can be loaded dynamically and are bound to the configuration stored in Zookeeper.&lt;/p&gt;

&lt;p&gt;The basis of the mechanism is a so-called &lt;strong&gt;Package Store&lt;/strong&gt;. It is a distributed file system that keeps its data on each Solr node in the &lt;strong&gt;$SOLR_HOME/filestore&lt;/strong&gt; directory and each of the files is described by metadata written in a JSON file. Of course, each file stores the checksum in its metadata for verification purposes. That way replacing the binary itself is not enough to load malicious versions of the plugin – the signature is still there and needs to be adjusted as well. That gives us a certain degree of security.&lt;/p&gt;

&lt;p&gt;On top of all of that, we have an API allowing us not only to manage the whole package repository but also single files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solr Package API
&lt;/h2&gt;

&lt;p&gt;Of course, our &lt;strong&gt;bin/solr&lt;/strong&gt; tool and installing the packages using it is not everything that Solr gives us. In addition to that we got the API that allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add files using the PUT HTTP method and the &lt;strong&gt;/api/cluster/files/{file_path}&lt;/strong&gt; endpoint&lt;/li&gt;
&lt;li&gt;retrieve files using the GET HTTP method and the &lt;strong&gt;/api/cluster/files/{file_path}&lt;/strong&gt; endpoint&lt;/li&gt;
&lt;li&gt;retrieve file metadata using the GET HTTP method and the &lt;strong&gt;/api/cluster/files/{file_path}?meta=true&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;retrieve files available at a given path using the GET HTTP method using the &lt;strong&gt;/api/cluster/files/{directory_path}&lt;/strong&gt; endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should remember that adding a file to Solr is not only about sending it to Solr. You need to sign it using a key that will be available to Solr – we saw that already.&lt;/p&gt;

&lt;p&gt;Similar to manipulating the files in the package repository we also have the option to manage packages. We have the option to add, remove and download the packages and their versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET on &lt;strong&gt;/api/cluster/package&lt;/strong&gt; to download the list of packages&lt;/li&gt;
&lt;li&gt;PUT on &lt;strong&gt;/api/cluster/package&lt;/strong&gt; to add a package&lt;/li&gt;
&lt;li&gt;DELETE on &lt;strong&gt;/api/cluster/package&lt;/strong&gt; to remove a package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example to add a package to Solr we could use a command like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-XPUT&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:8983/api/cluster/package'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-type:application/json'&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;  &lt;span class="s1"&gt;'{
 "add": {
  "package" : "sematext-example",
  "version" : "1.0.0",
  "files" : [
   "/test/sematext/1.0.0/sematext-example.jar"
  ]
 }
}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;The package management functionality brings a new way of extending Solr functionality. However, you should remember that flexibility doesn’t come for free. Having the option to use &lt;strong&gt;hot-deploy&lt;/strong&gt; and being able to install Solr extensions on the fly, without the need of bringing the whole cluster down carries limitations and security threats. Because of that remember not to add package repositories that you don’t know. Such repositories can be dangerous and can result in downloading and installing malicious code. The second thing to remember is that you shouldn’t add repositories that are not using SSL. Adding a repository that is not using SSL exposes you to the &lt;strong&gt;man in the middle&lt;/strong&gt; attack during which the files can be replaced on the fly leading to installing the malicious code. That can result in compromising your cluster, which may lead to data leaks or the whole environment being compromised. That is something that you should remember and keep your Solr secure no matter if you use package management or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The functionality of installing Solr extensions without the need to manually download them to each node, restarting the nodes and so on is very nice and tempting. Especially to those of us who use such extensions. However, please remember about security and the limitations of the mechanism. If we will be cautious we will have a way of extending Solr in a flexible way.&lt;/p&gt;

&lt;p&gt;Also keep in mind to &lt;a href="https://sematext.com/guides/solr/%23monitoring-solr-with-sematext" rel="noopener noreferrer"&gt;monitor your Solr&lt;/a&gt;, for example with software like our &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt; that can help you identify the bottlenecks and find the root cause of the problems with your instance or the whole cluster. Keep that in mind – you can’t fix what you can’t measure 🙂&lt;/p&gt;

</description>
      <category>solr</category>
      <category>plugin</category>
      <category>plugins</category>
    </item>
    <item>
      <title>Where Are Docker Logs Stored?</title>
      <dc:creator>Adnan Rahić</dc:creator>
      <pubDate>Tue, 05 May 2020 14:57:28 +0000</pubDate>
      <link>https://dev.to/sematext/where-are-docker-logs-stored-349d</link>
      <guid>https://dev.to/sematext/where-are-docker-logs-stored-349d</guid>
      <description>&lt;p&gt;There’s a short answer, and a long answer. The short answer, that will satisfy your needs in the vast majority of cases, is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/lib/docker/containers/&amp;lt;container_id&amp;gt;/&amp;lt;container_id&amp;gt;-json.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here you need to &lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;ship logs&lt;/a&gt; to a &lt;a href="https://sematext.com/logsene/" rel="noopener noreferrer"&gt;central location&lt;/a&gt;, and &lt;a href="https://www.freecodecamp.org/news/how-to-setup-log-rotation-for-a-docker-container-a508093912b2/" rel="noopener noreferrer"&gt;enable log rotation&lt;/a&gt; for your Docker containers. Let me elaborate on &lt;em&gt;why&lt;/em&gt; with the long answer below. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where Are Docker Container Logs Stored by Default?
&lt;/h2&gt;

&lt;p&gt;You see, by default, Docker containers emit logs to the &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt; output streams. &lt;strong&gt;Containers are stateless&lt;/strong&gt;, and the &lt;strong&gt;logs are stored on the Docker host in JSON files by default&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Why? &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;default logging driver is &lt;a href="https://docs.docker.com/config/containers/logging/json-file/" rel="noopener noreferrer"&gt;json-file&lt;/a&gt;&lt;/strong&gt;. What’s a logging driver? &lt;/p&gt;

&lt;p&gt;A logging driver is a mechanism for getting info from your running containers. Here’s a more elaborate explanation from the &lt;a href="https://docs.docker.com/config/containers/logging/configure/" rel="noopener noreferrer"&gt;Docker docs&lt;/a&gt;. There are several different log drivers you can use except for the default json-file, like syslog, &lt;a href="https://sematext.com/docs/integration/journald-integration/" rel="noopener noreferrer"&gt;journald&lt;/a&gt;, fluentd, or &lt;a href="https://github.com/sematext/logagent-js" rel="noopener noreferrer"&gt;logagent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These logs are emitted from output streams, annotated with the log origin, either &lt;code&gt;stdout&lt;/code&gt; or &lt;code&gt;stderr&lt;/code&gt;, and a timestamp. Each log file contains information about only one container and is in JSON format. Remember, &lt;strong&gt;one log file per container&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You find these JSON log files in the &lt;code&gt;/var/lib/docker/containers/&lt;/code&gt; directory on a Linux Docker host. The &lt;code&gt;&amp;lt;container_id&amp;gt;&lt;/code&gt; here is the id of the running container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/lib/docker/containers/&amp;lt;container_id&amp;gt;/&amp;lt;container_id&amp;gt;-json.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re not sure which id is related to which container, you can run the &lt;code&gt;docker ps&lt;/code&gt; command to list all running containers. The container id is located in the first column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps

&lt;span class="o"&gt;[&lt;/span&gt;Output]
CONTAINERID  IMAGE     COMMAND       CREATED    STATUS    PORTS    NAMES
cf74b6fce535 foo_image &lt;span class="s2"&gt;"node app.js"&lt;/span&gt; X min ago  Up X min  3000/tcp foo_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you know where the container logs are stored, and you can continue to troubleshoot and debug any issues that come up.&lt;/p&gt;

&lt;p&gt;That’s where &lt;a href="https://sematext.com/guides/docker-logs/" rel="noopener noreferrer"&gt;logging&lt;/a&gt; comes into play. You collect the logs with a log aggregator and store them in a place where they’ll be available forever. It’s dangerous to keep logs on the Docker host because they can build up over time and eat into your disk space. That’s why you should use a &lt;a href="https://sematext.com/logsene/" rel="noopener noreferrer"&gt;central location&lt;/a&gt; for your logs and &lt;a href="https://www.freecodecamp.org/news/how-to-setup-log-rotation-for-a-docker-container-a508093912b2/" rel="noopener noreferrer"&gt;enable log rotation&lt;/a&gt; for your Docker containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Docker Issues with Container Logs
&lt;/h2&gt;

&lt;p&gt;Docker has a &lt;a href="https://docs.docker.com/config/containers/logging/" rel="noopener noreferrer"&gt;dedicated API&lt;/a&gt; for working with logs. But, keep in mind, it will only work if you use the json-file log driver. I strongly recommend not changing the log driver! Let’s start debugging.&lt;/p&gt;

&lt;p&gt;First of all, to list all running containers, use the &lt;code&gt;docker ps&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, with the &lt;code&gt;docker logs&lt;/code&gt; command you can list the logs for a particular container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most of the time you’ll end up tailing these logs in real time, or checking the last few logs lines.&lt;/p&gt;

&lt;p&gt;Using the &lt;code&gt;--follow&lt;/code&gt; or &lt;code&gt;-f&lt;/code&gt; flag will &lt;code&gt;tail -f&lt;/code&gt; (follow) the Docker container logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--tail&lt;/code&gt; flag will show the last number of log lines you specify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; &lt;span class="nt"&gt;--tail&lt;/span&gt; N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-t&lt;/code&gt; or &lt;code&gt;--timestamp&lt;/code&gt; flag will show the timestamps of the log lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--details&lt;/code&gt; flag will show extra details about the log lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; &lt;span class="nt"&gt;--details&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if you only want to see specific logs? Luckily, grep works with Docker logs as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;pattern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will only show errors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once an application starts growing, you tend to start using Docker Compose. Don’t worry, it has a logs command as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display the logs from all services in the application defined in the Docker Compose configuration file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Docker Container Logs in a Central Location Using a Log Shipper
&lt;/h2&gt;

&lt;p&gt;With your infrastructure growing, you can rely on just using the Docker API to troubleshoot logs. You need to store all logs in a secure place, so you can analyze and troubleshoot any issues after-the-fact. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ngo2j3famco38irdrif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ngo2j3famco38irdrif.png" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need a steady influx of logs so you can get actionable insight into what is happening to your Docker containers. Setting up log rotation is just step one.&lt;/p&gt;

&lt;p&gt;By storing logs in one place you can also set up alerts that notify you if anything breaks, or whenever you’re experiencing unexpected behavior.&lt;/p&gt;

&lt;p&gt;Container logs can be a mix of plain text messages from start scripts and structured logs from applications, which makes it difficult for you to tell which log event belongs to what container and application.&lt;/p&gt;

&lt;p&gt;Although Docker log drivers can ship logs to &lt;a href="https://www.google.com/url?q=https://sematext.com/blog/best-log-management-tools/&amp;amp;sa=D&amp;amp;ust=1586240114907000&amp;amp;usg=AFQjCNHdp-WqXp3pySyzyw3A-xEZ00LvJA" rel="noopener noreferrer"&gt;log management tools&lt;/a&gt;, most of them don’t allow you to parse container logs. You need a separate tool called a log shipper, such as &lt;a href="https://sematext.com/blog/docker-container-monitoring-with-sematext/#toc-getting-started-with-logagent-1" rel="noopener noreferrer"&gt;Logagent&lt;/a&gt;, &lt;a href="https://sematext.com/blog/logstash-alternatives/" rel="noopener noreferrer"&gt;Logstash or rsyslog&lt;/a&gt; to structure and enrich the logs before shipping them.&lt;/p&gt;

&lt;p&gt;The solution is to have a container dedicated solely to logging and collecting logs. You deploy the dedicated logging container within your Docker environment. It will automatically &lt;a href="https://sematext.com/blog/log-aggregation/" rel="noopener noreferrer"&gt;aggregate logs&lt;/a&gt; from all containers, as well as monitor, &lt;a href="https://sematext.com/blog/log-analysis/" rel="noopener noreferrer"&gt;analyze,&lt;/a&gt; and store or forward them to a central location. &lt;/p&gt;

&lt;p&gt;This makes it easier to move containers between hosts and easily scale your infrastructure. It also lets you collect logs through various streams, including log events, Docker API data, stats, etc. &lt;/p&gt;

&lt;p&gt;This is what I’d suggest you use. By far the most reliable and convenient way of log collection is to use the json-file driver and set up a log shipper to ship the logs. You always have a local copy of logs on your server and you get the &lt;a href="https://sematext.com/guides/log-management/" rel="noopener noreferrer"&gt;advantage of centralized log management&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you were to use &lt;a href="https://sematext.com/docs/logagent/installation-docker/" rel="noopener noreferrer"&gt;Sematext Logagent&lt;/a&gt; there are a &lt;a href="https://sematext.com/blog/docker-container-monitoring-with-sematext/#toc-getting-started-with-logagent-1" rel="noopener noreferrer"&gt;few simple steps&lt;/a&gt; to follow in order to start sending logs to Sematext. After&lt;a href="https://sematext.com/docs/logs/quick-start/#creating-a-logs-app" rel="noopener noreferrer"&gt; creating a Logs App&lt;/a&gt;, run these commands in a terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull sematext/logagent

docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;--name&lt;/span&gt; st-logagent &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;LOGS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;YOUR_LOGS_TOKEN &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;LOGS_RECEIVER_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://logsene-receiver.sematext.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="se"&gt;\&lt;/span&gt;
  sematext/logagent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start sending all container logs to Sematext. &lt;/p&gt;

&lt;p&gt;You can read more about how Logagent works and how to use it for monitoring logs in our post on &lt;a href="https://sematext.com/blog/docker-container-monitoring-with-sematext/#toc-container-logs-0" rel="noopener noreferrer"&gt;Docker Container Monitoring with Sematext&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There we go, both a short and long answer to where Docker Container logs are stored. By default, Docker uses the json-file log driver that stores logs in dedicated directories on the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/var/lib/docker/containers/&amp;lt;container_id&amp;gt;/&amp;lt;container_id&amp;gt;-json.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The long answer, and what I’d suggest you do, is to set up a dedicated logging container that will structure and enrich your container logs, then send them to a central location. This makes troubleshooting and searching through logs much easier. But, you also get &lt;a href="https://sematext.com/alerts/" rel="noopener noreferrer"&gt;alerting&lt;/a&gt; which is the main point. You want to know what breaks before your users do.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hope you guys and girls enjoyed reading this as much as I enjoyed writing it. If you liked it, feel free to hit the share button so more people will see this tutorial. Until next time, be curious and have fun.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>logs</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Performance Best Practices: Running and Monitoring Express.js in Production</title>
      <dc:creator>Adnan Rahić</dc:creator>
      <pubDate>Tue, 28 Apr 2020 10:50:34 +0000</pubDate>
      <link>https://dev.to/sematext/performance-best-practices-running-and-monitoring-express-js-in-production-3e82</link>
      <guid>https://dev.to/sematext/performance-best-practices-running-and-monitoring-express-js-in-production-3e82</guid>
      <description>&lt;p&gt;What is the most important feature an Express.js application can have? Maybe using sockets for real-time chats or GraphQL instead of REST APIs? Come on, tell me. What’s the most amazing, sexy, and hyped feature you have in your Express.js application?&lt;/p&gt;

&lt;p&gt;Want to guess what mine is? &lt;strong&gt;Optimal performance with minimal downtime&lt;/strong&gt;. If your users can't use your application, what's the point of fancy features?&lt;/p&gt;

&lt;p&gt;In the past four years, I've learned that performant Express.js applications need to do four things well:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure minimal downtime&lt;/li&gt;
&lt;li&gt;Have predictable resource usage&lt;/li&gt;
&lt;li&gt;Scale effectively based on load&lt;/li&gt;
&lt;li&gt;Increase developer productivity by minimizing time spent on troubleshooting and debugging&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the past, I've talked a lot about how to improve&lt;a href="https://sematext.com/blog/top-nodejs-metrics-to-watch/" rel="noopener noreferrer"&gt; Node.js performance and related key metrics&lt;/a&gt; you have to monitor. There are several bad practices in Node.js you should avoid, such as blocking the thread and creating memory leaks, but also how to boost the performance of your application with the&lt;a href="https://sematext.com/docs/integration/express.js/#use-the-cluster-module-to-run-nodejs" rel="noopener noreferrer"&gt; cluster module&lt;/a&gt;,&lt;a href="https://sematext.com/docs/integration/express.js/#use-pm2-to-run-nodejs" rel="noopener noreferrer"&gt; PM2&lt;/a&gt;, &lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt;Nginx&lt;/a&gt; and&lt;a href="https://redis.io/" rel="noopener noreferrer"&gt; Redis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first step is to go back to basics and build up knowledge about the tool you are using. In our case the tool is JavaScript. Lastly, I'll cover how to add&lt;a href="https://sematext.com/docs/integration/express.js/#collected-expressjs-logs" rel="noopener noreferrer"&gt; structured logging&lt;/a&gt; and using&lt;a href="https://sematext.com/docs/integration/express.js/#collected-expressjs-metrics" rel="noopener noreferrer"&gt; metrics to pinpoint performance issues in Express.js&lt;/a&gt; applications like memory leaks.&lt;/p&gt;

&lt;p&gt;In&lt;a href="https://sematext.com/blog/nodejs-open-source-monitoring-tools/" rel="noopener noreferrer"&gt; a previous article&lt;/a&gt;, I explained how to monitor Node.js applications with five different open-source tools. They may not have full-blown features like the &lt;a href="https://sematext.com/docs/integration/express.js/" rel="noopener noreferrer"&gt;Sematext Express.js monitoring integration&lt;/a&gt;, Datadog, or New Relic, but keep in mind they’re open-source products and can hold their own just fine.&lt;/p&gt;

&lt;p&gt;In this article, I want to cover my experience from the last four years, mainly the best practices you should stick to, but also the bad things you should throw out right away. After reading this article you'll learn what you need to do to make sure you have a performant Express.js application with minimal downtime.&lt;/p&gt;

&lt;p&gt;In short, you'll learn about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Creating an intuitive structure for an &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express.js&lt;/a&gt; application&lt;/li&gt;
&lt;li&gt;  Hints for improving Express.js application performance&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://en.wikipedia.org/wiki/Test-driven_development" rel="noopener noreferrer"&gt; test-driven development&lt;/a&gt; and&lt;a href="https://www.freecodecamp.org/news/functional-programming-principles-in-javascript-1b8fc6c3563f/" rel="noopener noreferrer"&gt; functional programming paradigms in JavaScript&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Handling exceptions and errors gracefully&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://sematext.com/logsene/" rel="noopener noreferrer"&gt; Sematext Logs&lt;/a&gt; for logging and error handling&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://www.npmjs.com/package/dotenv" rel="noopener noreferrer"&gt; dotenv&lt;/a&gt; to handle environment variables and configurations&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://en.wikipedia.org/wiki/Systemd" rel="noopener noreferrer"&gt; Systemd&lt;/a&gt; for running Node.js scripts as a system process&lt;/li&gt;
&lt;li&gt;  Using the&lt;a href="https://nodejs.org/api/cluster.html" rel="noopener noreferrer"&gt; cluster module&lt;/a&gt; or&lt;a href="https://www.npmjs.com/package/pm2" rel="noopener noreferrer"&gt; PM2&lt;/a&gt; to enable cluster-mode load balancing&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://www.nginx.com/" rel="noopener noreferrer"&gt; Nginx&lt;/a&gt; as a reverse proxy and load balancer&lt;/li&gt;
&lt;li&gt;  Using Nginx and&lt;a href="https://redis.io/" rel="noopener noreferrer"&gt; Redis&lt;/a&gt; to cache API request results&lt;/li&gt;
&lt;li&gt;  Using&lt;a href="https://sematext.com/spm/" rel="noopener noreferrer"&gt; Sematext Monitoring&lt;/a&gt; for performance monitoring and troubleshooting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal for you is to use this to embrace Express.js best practices and a DevOps mindset. You want to have the best possible performance with minimal downtime and ensure high developer productivity. The goal is to solve issues quickly if they occur and trust me, they always do.&lt;/p&gt;

&lt;p&gt;Let's go back to basics, and talk a bit about Express.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Structure Express.js Applications
&lt;/h2&gt;

&lt;p&gt;Having an intuitive file structure will play a huge role in making your life easier. You will have an easier time adding new features as well as refactoring technical debt.&lt;/p&gt;

&lt;p&gt;The approach I stick to looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
  config/
    - configuration files
  controllers/
    - routes with provider functions as callback functions
  providers/
    - business logic for controller routes
  services/
    - common business logic used in the provider functions
  models/
    - database models
  routes.js
    - load all routes
  db.js
    - load all models
  app.js
    - load all of the above
test/
  unit/
    - unit tests
  integration/
    - integration tests
server.js
  - load the app.js file and listen on a port
(cluster.js)
  - load the app.js file and create a cluster that listens on a port
test.js
  - main test file that will run all test cases under the test/ directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup you can limit the file size to around 100 lines, making code reviews and troubleshooting much less of a nightmare. Have you ever had to review a pull request where every file has more than 500 lines of code? Guess what, it's not fun.&lt;/p&gt;

&lt;p&gt;There's a little thing I like to call separation of concerns. You don't want to create clusterfucks of logic in a single file. Separate concerns into their dedicated files. That way you can limit the context switching that happens when reading a single file. It's also very useful when merging to master often because it's much less prone to cause merge conflicts.&lt;/p&gt;

&lt;p&gt;To enforce rules like this across your team you can also set up a linter to tell you when you go over a set limit of lines in a file, as well as if a single line is above 100 characters long. One of my favorite settings, by the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Improve Express.js Performance and Reliability
&lt;/h2&gt;

&lt;p&gt;Express.js has a few well known best practices you should adhere to. Below are a few I think are the most important.&lt;/p&gt;

&lt;h4&gt;
  
  
  Set NODE_ENV=production
&lt;/h4&gt;

&lt;p&gt;Here's a quick hint to improve performance. Would you believe that only by setting the NODE_ENV environment variable to production will make your Express.js application&lt;a href="https://www.dynatrace.com/news/blog/the-drastic-effects-of-omitting-node-env-in-your-express-js-applications/" rel="noopener noreferrer"&gt; three times faster&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;In the terminal you can set it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, when running your server.js file you can add like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enable Gzip Compression
&lt;/h4&gt;

&lt;p&gt;Moving on, another important setting is to enable Gzip compression. First, install the compression npm package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i compression
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this snippet below to your code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;compression&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;compression&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using a reverse proxy with Nginx, you can enable it at that level instead. That's covered in the &lt;strong&gt;Enabling Gzip Compression with Nginx&lt;/strong&gt; section a bit further down.&lt;/p&gt;

&lt;h4&gt;
  
  
  Always Use Asynchronous Functions
&lt;/h4&gt;

&lt;p&gt;The last thing you want to do is to block the thread of execution. Never use synchronous functions! Like, seriously, don't. I mean it.&lt;/p&gt;

&lt;p&gt;What you should do instead is use&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt; Promises&lt;/a&gt; or Async/Await functions. If you by any chance only have access to sync functions you can easily wrap them in an Async function that will execute it outside of the main thread.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt; &lt;span class="nx"&gt;sync&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asyncWrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;syncFun&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;syncFun&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// the value will be returned outside of the main thread of execution&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;asyncWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you really can't avoid using a synchronous function then you can run them on a separate thread. To avoid blocking the main thread and bogging down your CPU you can create child processes or forks to handle CPU intensive tasks.&lt;/p&gt;

&lt;p&gt;An example would be that you have a web server that handles incoming requests. To avoid blocking this thread, you can spawn a&lt;a href="https://zaiste.net/nodejs-child-process-spawn-exec-fork-async-await/" rel="noopener noreferrer"&gt; child process&lt;/a&gt; to handle a CPU intensive task. Pretty cool. I explained this in more detail&lt;a href="https://sematext.com/blog/top-nodejs-metrics-to-watch/#toc-cpu-usage-metrics-for-nodejs-0" rel="noopener noreferrer"&gt; here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Make Sure To Do Logging Correctly
&lt;/h4&gt;

&lt;p&gt;To unify logs across your Express.js application, instead of using console.log(), you should use a logging agent to structure and &lt;a href="https://sematext.com/blog/log-aggregation/" rel="noopener noreferrer"&gt;collect logs in a central location&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can use any &lt;a href="https://sematext.com/blog/best-log-management-tools/" rel="noopener noreferrer"&gt;SaaS log management tool&lt;/a&gt; as the central location, like Sematext, Logz.io, Datadog, and many more. Think of it like a bucket where you keep logs so you can search and filter them later, but also get alerted about error logs and exceptions.&lt;/p&gt;

&lt;p&gt;I'm part of the integrations team here at&lt;a href="https://sematext.com/" rel="noopener noreferrer"&gt; Sematext&lt;/a&gt;, building&lt;a href="https://github.com/sematext?q=&amp;amp;type=source&amp;amp;language=javascript" rel="noopener noreferrer"&gt; open-source agents for Node.js&lt;/a&gt;. I put together this&lt;a href="https://github.com/sematext/sematext-agent-express" rel="noopener noreferrer"&gt; tiny open-source Express.js agent to collect logs&lt;/a&gt;. It can also collect metrics, but about that a bit further down. The agent is based on&lt;a href="https://www.npmjs.com/package/winston" rel="noopener noreferrer"&gt; Winston&lt;/a&gt; and&lt;a href="https://www.npmjs.com/package/morgan" rel="noopener noreferrer"&gt; Morgan&lt;/a&gt;. It tracks API request traffic with a middleware. This will give you per-route logs and data right away, which is crucial to track performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: Express.js &lt;em&gt;middleware&lt;/em&gt; functions are functions that have access to the&lt;a href="https://expressjs.com/en/4x/api.html#req" rel="noopener noreferrer"&gt; request object&lt;/a&gt; (req), the&lt;a href="https://expressjs.com/en/4x/api.html#res" rel="noopener noreferrer"&gt; response object&lt;/a&gt; (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.&lt;/strong&gt;  - &lt;em&gt;from &lt;a href="https://expressjs.com/en/guide/using-middleware.html" rel="noopener noreferrer"&gt;Using middleware&lt;/a&gt;, expressjs.com&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's how to add the logger and the middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sematext-agent-express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// At the top of your routes add the stHttpLoggerMiddleware to send API logs to Sematext&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Use the stLogger to send all types of logs directly to Sematext&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An info log.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A debug log.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A warning log.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An error log.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


 &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prior to requiring this agent you need to configure&lt;a href="https://github.com/sematext/sematext-agent-express#configure-environment" rel="noopener noreferrer"&gt; Sematext tokens as environment variables&lt;/a&gt;. In the dotenv section below, you will read more about configuring environment variables.&lt;/p&gt;

&lt;p&gt;Here's a quick preview of what you can get.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5x5m6esm8ze0m53tim46.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5x5m6esm8ze0m53tim46.png" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Handle Errors and Exceptions Properly
&lt;/h4&gt;

&lt;p&gt;When using Async/Await in your code, it's a best practice to rely on try-catch statements to handle errors and exceptions, while also using the unified Express logger to send the error log to a central location so you can use it to troubleshoot the issue with a stack trace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;baz&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Function &lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt; threw an exception.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also a best practice to configure a catch-all error middleware at the bottom of your routes.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Catch-All error handler.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will catch any error that gets thrown in your controllers. Another last step you can do is to add listeners on the process itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uncaughtException&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Uncaught exception&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandledRejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unhandled rejection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these tiny snippets you'll cover all the needed precautions for handling Express errors and log collection. You now have a solid base where you don't have to worry about losing track of errors and logs. From here you can&lt;a href="https://sematext.com/docs/alerts/creating-logs-alerts/" rel="noopener noreferrer"&gt; set up alerts in the Sematext Logs UI&lt;/a&gt; and get&lt;a href="https://sematext.com/docs/integration/alerts-slack-integration/#slack-api-integration" rel="noopener noreferrer"&gt; notified through Slack&lt;/a&gt; or E-mail, which is configured by default. Don't let your customers tell you your application is broken, know before they do.&lt;/p&gt;

&lt;h4&gt;
  
  
  Watch Out For Memory Leaks
&lt;/h4&gt;

&lt;p&gt;You can't catch errors before they happen. Some issues don't have root causes in exceptions breaking your application. They are silent and like memory leaks, they creep up on you when you least expect it. I explained how to avoid memory leaks in one of my&lt;a href="https://sematext.com/blog/top-nodejs-metrics-to-watch/#toc-memory-usage-and-leaks-metrics-for-nodejs-1" rel="noopener noreferrer"&gt; previous tutorials&lt;/a&gt;. What it all boils down to is to preempt any possibility of getting memory leaks.&lt;/p&gt;

&lt;p&gt;Noticing memory leaks is easier than you might think. If your process memory keeps growing steadily, while not periodically being reduced by garbage collection, you most likely have a memory leak. Ideally, you’d want to focus on preventing memory leaks rather than troubleshooting and debugging them. If you come across a memory leak in your application, it’s horribly difficult to track down the root cause.&lt;/p&gt;

&lt;p&gt;This is why you need to look into metrics about process and heap memory.&lt;/p&gt;

&lt;p&gt;Adding a metrics collector to your Express.js application, that will gather and store all key metrics in a central location where you can later slice and dice the data to get to the root cause of when a memory leak happened, and most importantly, why it happened.&lt;/p&gt;

&lt;p&gt;By importing a&lt;a href="https://github.com/sematext/sematext-agent-express#configure-agent" rel="noopener noreferrer"&gt; monitoring agent from the Sematext Agent Express&lt;/a&gt; module I mentioned above, you can enable the metric collector to&lt;a href="https://github.com/sematext/sematext-agent-express#metrics" rel="noopener noreferrer"&gt; store and visualize all the data&lt;/a&gt; in the Sematext Monitoring UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9drua6bqw9xtk7vwg23w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9drua6bqw9xtk7vwg23w.png" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the kicker, it's only one line of code. Add this snippet in your app.js file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stMonitor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sematext-agent-express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;stMonitor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// run the .start method on the stMonitor&lt;/span&gt;

&lt;span class="c1"&gt;// At the top of your routes add the stHttpLoggerMiddleware to send API logs to Sematext&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this you'll get access to several dashboards giving you key insight into everything going on with your Express.js application. You can filter and group the data to visualize processes, memory, CPU usage and HTTP requests and responses. But, what you should do right away is configure alerts to notify you when the process memory starts growing steadily without any increase in the request rate.&lt;/p&gt;

&lt;p&gt;Moving on from Express.js-specific hints and best practices, let's talk a bit about JavaScript and how to use the language itself in a more optimized and solid way.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Set Up Your JavaScript Environment
&lt;/h2&gt;

&lt;p&gt;JavaScript is neither object-oriented or functional. Rather, it's a bit of both. I'm quite biased towards using as many functional paradigms in my code as possible. However, one surpasses all others. Using pure functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pure Functions
&lt;/h3&gt;

&lt;p&gt;As the name suggests, pure functions are functions that do not mutate the outer state. They take parameters, do something with them, and return a value.&lt;/p&gt;

&lt;p&gt;Every single time you run them they will behave the same and return a value. This concept of throwing away state mutations and only relying on pure functions is something that has simplified my life to an enormous extent.&lt;/p&gt;

&lt;p&gt;Instead of using var or let only use const, and rely on pure functions to create new objects instead of mutating existing objects. This ties into using&lt;a href="https://www.youtube.com/watch?v=BMUiFMZr7vk" rel="noopener noreferrer"&gt; higher-order functions in JavaScript&lt;/a&gt;, like .map(), .reduce(), .filter(), and many more.&lt;/p&gt;

&lt;p&gt;How to practice writing functional code? Throw out every variable declaration except for const. Now try writing a controller. &lt;/p&gt;

&lt;h3&gt;
  
  
  Object Parameters
&lt;/h3&gt;

&lt;p&gt;JavaScript is a weakly typed language, and it can show its ugly head when dealing with function arguments. A function call can be passed one, none, or as many parameters as you want, even though the function declaration has a fixed number of arguments defined. What's even worse is that the order of the parameters are fixed and there is no way to enforce their names so you know what is getting passed along.&lt;/p&gt;

&lt;p&gt;It's absolute lunacy! All of it, freaking crazy! Why is there no way to enforce this? But, you can solve it somewhat by using objects as function parameters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param3&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;param2&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;param3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid parameters in function: foo.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;param1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;param2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;param3&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;98&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;81&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;== the same&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of these function calls will work identically. You can enforce the names of the parameters and you're not bound by order, making it much easier to manage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Freaking write tests, seriously!
&lt;/h3&gt;

&lt;p&gt;Do you know what's the best way to document your code, keep track of features and dependencies, increase community awareness, gain contributors, increase performance, increase developer productivity, have a nicer life, attract investors, raise a seed round, make millions selling your startup!?.... wait that got out of hand. &lt;/p&gt;

&lt;p&gt;Yes, you guessed it, writing tests is the answer.&lt;/p&gt;

&lt;p&gt;Let's get back on track. Write tests based on the features you want to build. Then write the feature. You will have a clear picture of what you want to build. During this process you will automatically start thinking about all the edge cases you would usually never consider.&lt;/p&gt;

&lt;p&gt;Trust me, TDD works.&lt;/p&gt;

&lt;p&gt;How to get started? Use something simple like&lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt; Mocha&lt;/a&gt; and&lt;a href="https://www.chaijs.com/" rel="noopener noreferrer"&gt; Chai&lt;/a&gt;. Mocha is a testing framework, while Chai is an assertion library.&lt;/p&gt;

&lt;p&gt;Install the npm packages with:&lt;/p&gt;

&lt;p&gt;npm i mocha chai&lt;/p&gt;

&lt;p&gt;Let's test the foo function from above. In your main test.js file add this snippet of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should be a function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should take one parameter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;98&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should throw error if the parameter is missing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should throw error if the parameter does not have 3 values&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should return the sum of three values&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;param3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;})).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to your scripts section in the package.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mocha"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run the tests by running a single command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test-mocha@1.0.0 &lt;span class="nb"&gt;test&lt;/span&gt; /path/to/your/expressjs/project
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; mocha

foo
  ✓ should be a &lt;span class="k"&gt;function&lt;/span&gt;
  ✓ should take one parameter
  ✓ should throw error &lt;span class="k"&gt;if &lt;/span&gt;the parameter is missing
  ✓ should throw error &lt;span class="k"&gt;if &lt;/span&gt;the parameter does not have 3 values
  ✓ should &lt;span class="k"&gt;return &lt;/span&gt;the &lt;span class="nb"&gt;sum &lt;/span&gt;of three values

 5 passing &lt;span class="o"&gt;(&lt;/span&gt;6ms&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Writing tests gives you a feeling of clarity. And it feels freaking awesome! I feel better already.&lt;/p&gt;

&lt;p&gt;With this out of my system I'm ready for DevOps topics. Let's move on to some automation and configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use DevOps Tools To Make Running Express.js in Production Easier
&lt;/h2&gt;

&lt;p&gt;Apart from the things you can do in the code, like you saw above, some things need to be configured in your environment and server setup. Starting from the basics, you need an easy way to manage environment variables, you also need to make sure your Express.js application restarts automatically in case it crashes.&lt;/p&gt;

&lt;p&gt;You also want to configure a reverse proxy and load balancer to expose your application, cache requests, and load balance traffic across multiple worker processes. The most important step in maintaining high performance is to add a metrics collector so you can visualize data across time and troubleshoot issues whenever they occur.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing Environment Variables in Node.js with dotenv
&lt;/h3&gt;

&lt;p&gt;Dotenv is an npm module that lets you load environment variables easily into any Node.js application by using a file.&lt;/p&gt;

&lt;p&gt;In the root of your project create a .env file. Here you'll add any environment variables you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NODE_ENV=production
DEBUG=false
LOGS_TOKEN=xxx-yyy-zzz
MONITORING_TOKEN=xxx-yyy-zzz
INFRA_TOKEN=xxx-yyy-zzz
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Loading this file is super simple. In your app.js file require dotenv at the top before anything else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// dotenv at the top&lt;/span&gt;
&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dotenv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// require any agents&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stLogger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sematext-agent-express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// require express and instantiate the app&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stHttpLoggerMiddleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dotenv will load a file named .env by default. If you want to have multiple dotenv files,&lt;a href="https://github.com/motdotla/dotenv#path" rel="noopener noreferrer"&gt; here's&lt;/a&gt; how you can configure them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make Sure the Application Restarts Automatically With Systemd or PM2
&lt;/h3&gt;

&lt;p&gt;JavaScript is a scripting language, obviously, the name says so. What does this mean? When you start your server.js file by running node server.js it will run the script as a process. However, if it fails, the process exits and there's nothing telling it to restart.&lt;/p&gt;

&lt;p&gt;Here's where using Systemd or PM2 comes into play. Either one works fine, but the Node.js maintainers urge us to use Systemd.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ensure Application Restarts with Systemd
&lt;/h4&gt;

&lt;p&gt;In short, Systemd is part of the building blocks of Linux operating systems. It runs and manages system processes. What you want is to run your Node.js process as a system service so it can recover from crashes.&lt;/p&gt;

&lt;p&gt;Here's how you do it. On your VM or server, create a new file under &lt;code&gt;/lib/systemd/system/&lt;/code&gt; called app.service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# /lib/systemd/system/fooapp.service&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit]
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Node.js as a system service.
&lt;span class="nv"&gt;Documentation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://example.com
&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target
&lt;span class="o"&gt;[&lt;/span&gt;Service]
&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;simple
&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ubuntu
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/node /path/to/your/express/project/server.js
&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on-failure
&lt;span class="o"&gt;[&lt;/span&gt;Install]
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two important lines in this file are &lt;code&gt;ExecStart&lt;/code&gt; and &lt;code&gt;Restart&lt;/code&gt;. The &lt;code&gt;ExecStart&lt;/code&gt; says that the &lt;code&gt;/usr/bin/node&lt;/code&gt; binary will start your &lt;code&gt;server.js&lt;/code&gt; file. Make sure to add an absolute path to your &lt;code&gt;server.js&lt;/code&gt; file. The &lt;code&gt;Restart=on-failure&lt;/code&gt; makes sure to restart the application if it crashes. Exactly what you're looking for.&lt;/p&gt;

&lt;p&gt;Once you save the &lt;code&gt;fooapp.service&lt;/code&gt; file, reload your daemon and start the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl daemon-reload
systemctl start fooapp
systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;fooapp
systemctl status fooapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The status command will show you the application is running as a system service. The enable command makes sure it starts on boot. That was easier than you thought, am I right?&lt;/p&gt;

&lt;h4&gt;
  
  
  Ensure Application Restarts with PM2
&lt;/h4&gt;

&lt;p&gt;PM2 has been around for a few years. They utilize a custom-built script that manages and runs your server.js file. It is simpler to set up, but comes with the overhead of having another Node.js process that acts as a Master process, like a manager, for your Express.js application processes.&lt;/p&gt;

&lt;p&gt;First you need to install PM2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; pm2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you start your application by running this command in the root directory of your Express.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 start server.js &lt;span class="nt"&gt;-i&lt;/span&gt; max
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-i max&lt;/code&gt; flag will make sure to start the application in cluster-mode, spawning as many workers as there are CPU cores on the server.&lt;/p&gt;

&lt;p&gt;Mentioning cluster-mode is the perfect segue into the next section about load balancing and reverse proxies and caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Load Balancing and Reverse Proxies
&lt;/h3&gt;

&lt;p&gt;Load balancing can be done with both the Node.js cluster module or with Nginx. I'll show you my preferred setup, which is also what the peeps over at Node.js think is the right way to go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Load Balancing with the Cluster Module
&lt;/h4&gt;

&lt;p&gt;The built-in cluster module in Node.js lets you spawn worker processes that will serve your application. It's based on the&lt;a href="https://nodejs.org/api/child_process.html" rel="noopener noreferrer"&gt; child_process&lt;/a&gt; implementation and, luckily for us, is very easy to set up if you have a basic Express.js application.&lt;/p&gt;

&lt;p&gt;You only really need to add one more file. Create a file called &lt;code&gt;cluster.js&lt;/code&gt; and paste this snippet of code into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cluster&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numCPUs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cpus&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;masterProcess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numCPUs&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;childProcess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isMaster&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;masterProcess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;childProcess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cluster&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down what's happening here. When you start the &lt;code&gt;cluster.js&lt;/code&gt; file with &lt;code&gt;node cluster.js&lt;/code&gt; the cluster module will detect that it is running as a master process. In that case it invokes the &lt;code&gt;masterProcess()&lt;/code&gt; function. The &lt;code&gt;masterProcess()&lt;/code&gt; function counts how many CPU cores the server has and invokes the &lt;code&gt;cluster.fork()&lt;/code&gt; function that many times. Once the &lt;code&gt;cluster.fork()&lt;/code&gt; function is invoked the cluster module will detect it is running as a child process and invoke the &lt;code&gt;childProcess()&lt;/code&gt; function, which then tells the Express.js server to &lt;code&gt;.listen()&lt;/code&gt; on a port. All these processes are running on the same port. It's possible due to something called an IPC connection. Read more about that&lt;a href="https://nodejs.org/api/cluster.html#cluster_how_it_works" rel="noopener noreferrer"&gt; here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;cluster.on('exit')&lt;/code&gt; event listener will restart a worker process if it fails.&lt;/p&gt;

&lt;p&gt;With this setup you can now edit the &lt;code&gt;ExecStart&lt;/code&gt; field in the &lt;code&gt;fooapp.service&lt;/code&gt; Systemd service file to run the &lt;code&gt;cluster.js&lt;/code&gt; file instead.&lt;/p&gt;

&lt;p&gt;Replace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/node /path/to/your/express/project/server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/node /path/to/your/express/project/cluster.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload the Systemd daemon and restart the &lt;code&gt;fooapp.service&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl daemon-reload
systemctl restart fooapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it. You've added load balancing to your Express.js application. Now it will scale across all the CPUs on your server.&lt;/p&gt;

&lt;p&gt;However, this will only work for a single-server setup. If you want to have multiple servers, you need Nginx.&lt;/p&gt;

&lt;h4&gt;
  
  
  Adding a Reverse Proxy with Nginx
&lt;/h4&gt;

&lt;p&gt;One of the primal laws of running Node.js applications is to never expose them on port 80 or 443. You should always use a reverse proxy to direct traffic to your application. Nginx is the most common tool you use with Node.js to achieve this. It's a web server that can act as both a reverse proxy and load balancer.&lt;/p&gt;

&lt;p&gt;Installing Nginx is rather straightforward, for Ubuntu it would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update
apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to check the Nginx installation instructions if you're using another operating system.&lt;/p&gt;

&lt;p&gt;Nginx should start right away, but just in case make sure to check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status nginx

&lt;span class="o"&gt;[&lt;/span&gt;Output]
nginx.service - A high performance web server and a reverse proxy server
  Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/lib/systemd/system/nginx.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
  Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Fri 2018-04-20 16:08:19 UTC&lt;span class="p"&gt;;&lt;/span&gt; 3 days ago
    Docs: man:nginx&lt;span class="o"&gt;(&lt;/span&gt;8&lt;span class="o"&gt;)&lt;/span&gt;
Main PID: 2369 &lt;span class="o"&gt;(&lt;/span&gt;nginx&lt;span class="o"&gt;)&lt;/span&gt;
  Tasks: 2 &lt;span class="o"&gt;(&lt;/span&gt;limit: 1153&lt;span class="o"&gt;)&lt;/span&gt;
  CGroup: /system.slice/nginx.service
          ├─2369 nginx: master process /usr/sbin/nginx &lt;span class="nt"&gt;-g&lt;/span&gt; daemon on&lt;span class="p"&gt;;&lt;/span&gt; master_process on&lt;span class="p"&gt;;&lt;/span&gt;
          └─2380 nginx: worker process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it is not started, go ahead and run this command to start it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl start nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you have Nginx running, you need to edit the configuration to enable a reverse proxy. You can find the Nginx configuration file in the &lt;code&gt;/etc/nginx/&lt;/code&gt; directory. The main configuration file is called &lt;code&gt;nginx.conf&lt;/code&gt;, while there are additional snippets in the &lt;code&gt;etc/nginx/sites-available/&lt;/code&gt; directory. The default server configuration is found here and is named &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To just enable a reverse proxy, open up the &lt;code&gt;default&lt;/code&gt; configuration file and edit it so it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# change the port if needed&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and restart the Nginx service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will route all traffic hitting port 80 to your Express.js application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Load Balancing with Nginx
&lt;/h4&gt;

&lt;p&gt;If you want to take it a step further, and enable load balancing, here's how to do it.&lt;/p&gt;

&lt;p&gt;Now, edit the main &lt;code&gt;nginx.conf&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;upstream&lt;/span&gt; &lt;span class="s"&gt;fooapp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="nf"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="s"&gt;domain2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="s"&gt;domain3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kn"&gt;...&lt;/span&gt;
  &lt;span class="err"&gt;}&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding this &lt;code&gt;upstream&lt;/code&gt; section will create a server group that will load balance traffic across all the servers you specify.&lt;/p&gt;

&lt;p&gt;You also need to edit the &lt;code&gt;default&lt;/code&gt; configuration file to point the reverse proxy to this &lt;code&gt;upstream&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://fooapp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the files and restart the Nginx service once again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enabling Caching with Nginx
&lt;/h4&gt;

&lt;p&gt;Caching is important to reduce response times for API endpoints, and resources that don't change very often.&lt;/p&gt;

&lt;p&gt;Once again edit the nginx.conf file, and add this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;proxy_cache_path&lt;/span&gt; &lt;span class="n"&gt;/data/nginx/cache&lt;/span&gt; &lt;span class="s"&gt;levels=1:2&lt;/span&gt;   &lt;span class="s"&gt;keys_zone=STATIC:10m&lt;/span&gt;
  &lt;span class="s"&gt;inactive=24h&lt;/span&gt; &lt;span class="s"&gt;max_size=1g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open up the &lt;code&gt;default&lt;/code&gt; configuration file again. Add these lines of code as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_pass&lt;/span&gt;             &lt;span class="s"&gt;http://fooapp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;       &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_buffering&lt;/span&gt;       &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_cache&lt;/span&gt;           &lt;span class="s"&gt;STATIC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_cache_valid&lt;/span&gt;      &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="s"&gt;1d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;proxy_cache_use_stale&lt;/span&gt;  &lt;span class="s"&gt;error&lt;/span&gt; &lt;span class="s"&gt;timeout&lt;/span&gt; &lt;span class="s"&gt;invalid_header&lt;/span&gt; &lt;span class="s"&gt;updating&lt;/span&gt;
            &lt;span class="s"&gt;http_500&lt;/span&gt; &lt;span class="s"&gt;http_502&lt;/span&gt; &lt;span class="s"&gt;http_503&lt;/span&gt; &lt;span class="s"&gt;http_504&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save both files and restart the Nginx service once again.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enabling Gzip Compression with Nginx
&lt;/h4&gt;

&lt;p&gt;To improve performance even more, go ahead and enable Gzip. In the server block of your Nginx configuration file add these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kn"&gt;gzip&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;gzip_types&lt;/span&gt;     &lt;span class="nc"&gt;text/plain&lt;/span&gt; &lt;span class="nc"&gt;application/xml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;gzip_proxied&lt;/span&gt;    &lt;span class="s"&gt;no-cache&lt;/span&gt; &lt;span class="s"&gt;no-store&lt;/span&gt; &lt;span class="s"&gt;private&lt;/span&gt; &lt;span class="s"&gt;expired&lt;/span&gt; &lt;span class="s"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kn"&gt;gzip_min_length&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to check out more configuration options about Gzip compression in Nginx,&lt;a href="https://docs.nginx.com/nginx/admin-guide/web-server/compression/" rel="noopener noreferrer"&gt; check this out&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Enabling Caching with Redis
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; in an in-memory data store, which is often used as a cache.&lt;/p&gt;

&lt;p&gt;Installing it on Ubuntu is rather simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt update
apt &lt;span class="nb"&gt;install &lt;/span&gt;redis-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will download and install Redis and its dependencies. There is one important configuration change to make in the Redis configuration file that was generated during the installation.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;/etc/redis/redis.conf&lt;/code&gt; file. You have to change one line from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supervised no
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;supervised systemd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the only change you need to make to the Redis configuration file at this point, so save and close it when you are finished. Then, restart the Redis service to reflect the changes you made to the configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl restart redis
systemctl status redis

&lt;span class="o"&gt;[&lt;/span&gt;Output]
● redis-server.service - Advanced key-value store
  Loaded: loaded &lt;span class="o"&gt;(&lt;/span&gt;/lib/systemd/system/redis-server.service&lt;span class="p"&gt;;&lt;/span&gt; enabled&lt;span class="p"&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class="o"&gt;)&lt;/span&gt;
  Active: active &lt;span class="o"&gt;(&lt;/span&gt;running&lt;span class="o"&gt;)&lt;/span&gt; since Wed 2018-06-27 18:48:52 UTC&lt;span class="p"&gt;;&lt;/span&gt; 12s ago
    Docs: http://redis.io/documentation,
          man:redis-server&lt;span class="o"&gt;(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt;
Process: 2421 &lt;span class="nv"&gt;ExecStop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/bin/kill &lt;span class="nt"&gt;-s&lt;/span&gt; TERM &lt;span class="nv"&gt;$MAINPID&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited, &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0/SUCCESS&lt;span class="o"&gt;)&lt;/span&gt;
Process: 2424 &lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/redis-server /etc/redis/redis.conf &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;exited, &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0/SUCCESS&lt;span class="o"&gt;)&lt;/span&gt;
Main PID: 2445 &lt;span class="o"&gt;(&lt;/span&gt;redis-server&lt;span class="o"&gt;)&lt;/span&gt;
  Tasks: 4 &lt;span class="o"&gt;(&lt;/span&gt;limit: 4704&lt;span class="o"&gt;)&lt;/span&gt;
  CGroup: /system.slice/redis-server.service
          └─2445 /usr/bin/redis-server 127.0.0.1:6379
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next you install the&lt;a href="https://www.npmjs.com/package/redis" rel="noopener noreferrer"&gt; redis npm module&lt;/a&gt; to access Redis from your application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can require it in your application and start caching request responses. Let me show you an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSomethingFromDatabase&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Set data to Redis&lt;/span&gt;
    &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;

  &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="c1"&gt;// If data exists return the cached value&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;// If data does not exist, proceed to the getSomethingFromDatabase function&lt;/span&gt;
   &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/data/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getSomethingFromDatabase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server running on Port &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This piece of code will cache the response from the database as a JSON string in the Redis cache for 3600 seconds. You can change this based on your own needs.&lt;/p&gt;

&lt;p&gt;With this, you've configured key settings to improve performance. But, you've also introduced additional possible points of failure. What if Nginx crashes or Redis overloads your disk space? How do you troubleshoot that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable VM/Server-Wide Monitoring and Logging
&lt;/h3&gt;

&lt;p&gt;Ideally, you'd configure &lt;a href="https://sematext.com/docs/monitoring/infrastructure/" rel="noopener noreferrer"&gt;an Infrastructure Agent on your VM or server&lt;/a&gt; to gather metrics and logs and send them to a central location. That way you can keep track of all infrastructure metrics like CPU, memory, disk usage, processes, etc.&lt;/p&gt;

&lt;p&gt;This way you can keep an eye on your whole infrastructure, including CPU, memory and disk usage, as well as all the separate processes while running your application in cluster-mode.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6stle4bkm43iwvtemaez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6stle4bkm43iwvtemaez.png" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, we do need to know what's going on with Nginx first. You can configure the &lt;code&gt;stub_status&lt;/code&gt; to show Nginx metrics, but that doesn't really give you any actionable insight. But, you can install an&lt;a href="https://sematext.com/docs/integration/nginx/" rel="noopener noreferrer"&gt; Nginx Integration&lt;/a&gt; and get insight into Nginx metrics alongside your&lt;a href="https://sematext.com/docs/integration/express.js/" rel="noopener noreferrer"&gt; Express.js Integration&lt;/a&gt; in Sematext Cloud.&lt;/p&gt;

&lt;p&gt;Why is monitoring Nginx important? Nginx is the entry point to your application. If it fails, your whole application fails. Your Node.js instance can be fine, but Nginx stops responding and your website goes down. You'll have no clue it's down because the Express.js application is still running without any issues.&lt;/p&gt;

&lt;p&gt;You have to keep an eye on all the points of failure in your system. That's why having proper alerting in place is so crucial. If you want to learn more about alerting you can&lt;a href="https://sematext.com/docs/guide/alerts-guide/" rel="noopener noreferrer"&gt; read this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Same goes for Redis. To keep an eye on it, check out ways to monitor Redis, &lt;a href="https://haydenjames.io/using-redis-stat-for-redis-statistics-tracking/" rel="noopener noreferrer"&gt;here&lt;/a&gt; or&lt;a href="https://sematext.com/docs/integration/redis/" rel="noopener noreferrer"&gt; here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That wraps up the DevOps tools and best practices you should stick to. What a ride that was! If you want to delve deeper into learning about DevOps and tooling, check out this guide my co-worker wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;It took me the better part of four years to start using proper tooling and adhering to best practices. In the end, I just want to point out the most important part of your application is to be available and performant. Otherwise, you won't see any users stick around. If they can't use your application, what's the point?&lt;/p&gt;

&lt;p&gt;The idea behind this article was to cover best practices you should stick to, but also the bad practices to stay away from.&lt;/p&gt;

&lt;p&gt;You've learned many new things in this Express.js tutorial. From optimizing Express.js itself, creating an intuitive project structure and optimizing for performance to learning about JavaScript best practices and test-driven development. You've also learned about error handling, logging and monitoring.&lt;/p&gt;

&lt;p&gt;After all this, you can say with certainty that you've had an introduction to DevOps culture. What does that mean? Well, making sure to write reliable and performant software with test coverage, while maintaining the best possible developer productivity. That's how we as engineers continue loving our job. Otherwise, it's all mayhem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hope you all enjoyed reading this as much as I enjoyed writing it. If you liked it, feel free to hit the share button so more people will see this tutorial. Until next time, be curious and have fun.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Running and Deploying Elasticsearch Operator on Kubernetes</title>
      <dc:creator>Adnan Rahić</dc:creator>
      <pubDate>Mon, 09 Mar 2020 18:36:33 +0000</pubDate>
      <link>https://dev.to/sematext/running-and-deploying-elasticsearch-operator-on-kubernetes-2509</link>
      <guid>https://dev.to/sematext/running-and-deploying-elasticsearch-operator-on-kubernetes-2509</guid>
      <description>&lt;p&gt;Have you ever grown tired of running the same &lt;code&gt;kubectl&lt;/code&gt; commands again and again? Well, the good folks over at the Kubernetes team understand you. With the addition of custom resources and the operator pattern, you can now make use of extensions, or addons as I like to call them, to the Kubernetes API that help you manage applications and components.&lt;/p&gt;

&lt;p&gt;Operators follow Kubernetes principles including the&lt;a href="https://kubernetes.io/docs/concepts/#kubernetes-control-plane" rel="noopener noreferrer"&gt; control loop&lt;/a&gt;. The Operator Pattern is set out to help DevOps teams manage a service or set of services by automating repeatable tasks.&lt;/p&gt;

&lt;p&gt;This article will show you the pros and cons of using the Operator Pattern versus StatefulSets, as I explained in our previous &lt;a href="https://sematext.com/blog/kubernetes-elasticsearch/" rel="noopener noreferrer"&gt;tutorial about Running and Deploying Elasticsearch on Kubernetes&lt;/a&gt;. It will also guide you through installing and running the Elasticsearch Operator on a Kubernetes cluster. I will also explain how to quickly set up basic monitoring with the &lt;a href="https://sematext.com/docs/integration/elasticsearch/" rel="noopener noreferrer"&gt;Sematext Elasticsearch monitoring integration&lt;/a&gt;.  You can also peek at &lt;a href="https://sematext.com/kubernetes/" rel="noopener noreferrer"&gt;Kubernetes monitoring&lt;/a&gt; integration on your own.&lt;/p&gt;

&lt;p&gt;Keep in mind, there are no silver bullets. Both solutions are valid, but are useful for different scenarios. At &lt;a href="https://sematext.com/" rel="noopener noreferrer"&gt;Sematext&lt;/a&gt; we're using the StatefulSet approach, and it's working great for us.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://sematext.com/guides/elasticsearch/" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; Operator I'll be using in this tutorial is the official Operator from Elastic. It automates the deployment, provisioning, management, and orchestration of &lt;a href="https://sematext.com/blog/kubernetes-elasticsearch/" rel="noopener noreferrer"&gt;Elasticsearch on Kubernetes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that out of the way, let's jump into the tutorial!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5ghpw5gciceegih8huf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft5ghpw5gciceegih8huf.png" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Kubernetes Operators?
&lt;/h2&gt;

&lt;p&gt;Operators are extensions to Kubernetes that use custom resources to manage applications. By using the&lt;a href="https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/" rel="noopener noreferrer"&gt; CustomResourceDefinition&lt;/a&gt; (CRD) API resource, you can define custom resources. In this tutorial you'll learn how to create a custom resource in a separate namespace.&lt;/p&gt;

&lt;p&gt;When you define a CRD object, it creates a new custom resource with a name and schema that you specify. What's so cool about this? Well, you don't have to write a custom configuration to handle the custom resource. The Kubernetes API does it all for you. It serves and handles the storage of your custom resource.&lt;/p&gt;

&lt;p&gt;The point of using the Operator Pattern is to help you, the DevOps engineer, automate repeatable tasks. It captures how you can write code to automate a task beyond what Kubernetes itself provides.&lt;/p&gt;

&lt;p&gt;You deploy an Operator by adding the Custom Resource Definition and Controller to your cluster. The Controller will normally run outside of the&lt;a href="https://kubernetes.io/docs/reference/glossary/?all=true#term-control-plane" rel="noopener noreferrer"&gt; control plane&lt;/a&gt;, much as you would run any containerized application. More about that a bit further down. Let me explain what the Elasticsearch Operator is first.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Elasticsearch Operator?
&lt;/h2&gt;

&lt;p&gt;The Elasticsearch Operator automates the process of managing Elasticsearch on Kubernetes.&lt;/p&gt;

&lt;p&gt;There are a few different&lt;a href="https://github.com/upmc-enterprises/elasticsearch-operator" rel="noopener noreferrer"&gt; Elasticsearch Operators&lt;/a&gt; you can choose from. Some of them are made by active open-source contributors, however only one is written and maintained by Elastic.&lt;/p&gt;

&lt;p&gt;However, I won't go into details about any of them except for the official&lt;a href="https://github.com/elastic/cloud-on-k8s" rel="noopener noreferrer"&gt; ECK Operator built by Elastic&lt;/a&gt;. For the rest of this tutorial, I'll demo how to manage and run this particular Elasticsearch Operator.&lt;/p&gt;

&lt;p&gt;ECK simplifies deploying the whole Elastic stack on Kubernetes, giving you tools to automate and streamline critical operations. You can add, remove, and update resources with ease. Like playing with Lego bricks, changing things around is incredibly simple. It also makes it much easier to handle operational and cluster administration tasks. What is streamlined?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Managing multiple clusters&lt;/li&gt;
&lt;li&gt;  Upgrading versions&lt;/li&gt;
&lt;li&gt;  Scaling cluster capacity&lt;/li&gt;
&lt;li&gt;  Changing cluster configuration&lt;/li&gt;
&lt;li&gt;  Dynamically scaling storage&lt;/li&gt;
&lt;li&gt;  Scheduling backups&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Use the Elasticsearch Operator: Pros and Cons?
&lt;/h2&gt;

&lt;p&gt;When I first learned about the Operator Pattern, I had an overwhelming feeling of hype. I wanted it to be better than the "old" way. I was hoping the added automation would make managing and deploying applications on Kubernetes much easier. I was literally hoping it would be the same breakthrough as Helm.&lt;/p&gt;

&lt;p&gt;In the end, it's not. Well, at least not yet. If you compare the stars of the most popular&lt;a href="https://github.com/bitnami/charts/tree/master/bitnami/elasticsearch" rel="noopener noreferrer"&gt; Helm charts&lt;/a&gt; that configure Elasticsearch StatefulSets versus the&lt;a href="https://github.com/elastic/cloud-on-k8s" rel="noopener noreferrer"&gt; official Elasticsearch Operator&lt;/a&gt;, they're neck-and-neck. We still seem to be a bit conflicted about what to use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pld99877duivfezthni.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pld99877duivfezthni.png" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Elasticsearch Operator vs. StatefulSet
&lt;/h3&gt;

&lt;p&gt;The Elasticsearch Operator essentially creates an additional namespace that houses tools to automate the process of creating Elasticsearch resources in your default namespace. It's literally an addon you add to your Kubernetes system to handle Elasticsearch-specific resources.&lt;/p&gt;

&lt;p&gt;This gives you more automation but also abstracts away things you might need more fine-tuned control over. Configuring your own StatefulSets can often be the better approach because this is the way the community is used to configuring Elasticsearch clusters. It also gives you more control.&lt;/p&gt;

&lt;p&gt;However, the Operator can do things that are not available with the StatefulSets. It uses Kubernetes resources in the background to automate your work with some additional features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  S3 snapshots of indexes&lt;/li&gt;
&lt;li&gt;  Automatic TLS - the operator automatically generates secrets&lt;/li&gt;
&lt;li&gt;  Spread loads across zones&lt;/li&gt;
&lt;li&gt;  Support for Kibana and Cerebro&lt;/li&gt;
&lt;li&gt;  Instrumentation with statsd&lt;/li&gt;
&lt;li&gt;  Secure by default, with encryption enabled and password protected&lt;/li&gt;
&lt;li&gt;  Official Operator maintained by Elastic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Use the Elasticsearch Operator?
&lt;/h3&gt;

&lt;p&gt;If you want to get up and running quickly, choose the Operator. You'll get all of this out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Elasticsearch, Kibana and APM Server deployments&lt;/li&gt;
&lt;li&gt;  TLS certificates management&lt;/li&gt;
&lt;li&gt;  Safe Elasticsearch cluster configuration &amp;amp; topology changes&lt;/li&gt;
&lt;li&gt;  Persistent volumes usage&lt;/li&gt;
&lt;li&gt;  Custom node configuration and attributes&lt;/li&gt;
&lt;li&gt;  Secure settings keystore updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, keep in mind there are downsides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Stay Away From the Elasticsearch Operator?
&lt;/h3&gt;

&lt;p&gt;Like with any new and exciting tool, there are a few issues. The biggest one being that it's a totally new tool you need to learn. Here are my reasons for staying away from the Operator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  An additional tool to learn&lt;/li&gt;
&lt;li&gt;  Additional Kubernetes resources in a separate namespace to worry about&lt;/li&gt;
&lt;li&gt;  Additional resources create overhead&lt;/li&gt;
&lt;li&gt;  Less fine-tuned control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of what the Elasticsearch Operator offers is already available with prebuilt Helm charts.&lt;/p&gt;

&lt;p&gt;With that out of the way. Let's start by building something!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Run and Deploy the Elasticsearch Operator on Kubernetes
&lt;/h2&gt;

&lt;p&gt;Installing the Elasticsearch Operator is as simple as running one command. Don't believe me? Follow along and find out for yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftch9hsh3ep1lyktth80l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftch9hsh3ep1lyktth80l.png" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow along with this tutorial you’ll need a few things first:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A Kubernetes cluster with role-based access control (RBAC) enabled.

&lt;ul&gt;
&lt;li&gt;  Ensure your cluster has enough resources available, and if not scale your cluster by adding more Kubernetes Nodes. You’ll deploy a 3-Pod Elasticsearch cluster. I’d suggest you have 3 Kubernetes Nodes with at least 4GB of RAM and 10GB of storage.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  The &lt;code&gt;kubectl&lt;/code&gt; command-line tool installed on your local machine, configured to connect to your cluster. You can read more about how to install kubectl&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/" rel="noopener noreferrer"&gt; in the official documentation&lt;/a&gt;.&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installing the Elasticsearch Operator
&lt;/h3&gt;

&lt;p&gt;This command will install&lt;a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" rel="noopener noreferrer"&gt; custom resource definitions&lt;/a&gt; and the Operator with RBAC rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://download.elastic.co/downloads/eck/1.0.0/all-in-one.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've installed the Operator, you can check the resources by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; elastic-system get all
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                     READY   STATUS   RESTARTS   AGE
pod/elastic-operator-0   1/1     Running   0         18s
​
NAME                             TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
service/elastic-webhook-server   ClusterIP   10.96.52.149   &amp;lt;none&amp;gt;        443/TCP   19s
​
NAME                               READY   AGE
statefulset.apps/elastic-operator   1/1     19s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see the Operator will live under the elastic-system namespace. You can monitor the logs of the Operator's StatefulSet with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; elastic-system logs &lt;span class="nt"&gt;-f&lt;/span&gt; statefulset.apps/elastic-operator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A better way of monitoring logs on a cluster-level is to add the &lt;a href="https://sematext.com/docs/agents/sematext-agent/kubernetes/installation/#sematext-operator" rel="noopener noreferrer"&gt;Sematext Operator&lt;/a&gt; to collect these logs and send them to a central location, alongside performance metrics about your Elasticsearch cluster. It’s pretty straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/sematext/sematext-operator/master/bundle.yaml

&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: sematext.com/v1alpha1
kind: SematextAgent
metadata:
  name: sematext-agent
spec:
  region: &amp;lt;"US" or "EU"&amp;gt;
  containerToken: YOUR_CONTAINER_TOKEN
  logsToken: YOUR_LOGS_TOKEN
  infraToken: YOUR_INFRA_TOKEN
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All you need are these two commands above, and you’re set to go. Next up, let's take a look at the CRDs that were created as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get crd
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                                           CREATED AT
apmservers.apm.k8s.elastic.co                  2020-02-05T15:46:33Z
elasticsearches.elasticsearch.k8s.elastic.co   2020-02-05T15:46:33Z
kibanas.kibana.k8s.elastic.co                  2020-02-05T15:46:33Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the APIs you'll have access to, in order to streamline the process of creating and managing Elasticsearch resources in your Kubernetes cluster. Next up, let's deploy an Elasticsearch cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying the Elasticsearch Cluster
&lt;/h3&gt;

&lt;p&gt;Once the Operator is installed you'll get the access  elasticsearch.k8s.elastic.co/v1 API. Now you can spin up an Elasticsearch server in no time. Run this command to create an Elasticsearch cluster with a single node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 1
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a minute to start. You can check the cluster health during the creation process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get elasticsearch
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME           HEALTH   NODES   VERSION   PHASE   AGE
elasticsearch   green    1       7.5.2     Ready   61s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a running Elasticsearch Pod, which is tied to a StatefulSet in the default namespace. Alongside this, you also have two Services you can expose to access the Pod.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                             READY   STATUS   RESTARTS   AGE
pod/elasticsearch-es-default-0   1/1     Running   0         2m18s
NAME                               TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
service/elasticsearch-es-default   ClusterIP   None           &amp;lt;none&amp;gt;       &amp;lt;none&amp;gt;     2m18s
service/elasticsearch-es-http     ClusterIP   10.96.192.180   &amp;lt;none&amp;gt;        9200/TCP   2m19s
service/kubernetes                 ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP   2d2h
NAME                                       READY   AGE
statefulset.apps/elasticsearch-es-default   1/1     2m18s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make sure your Pod is working, check its logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl logs elasticsearch-es-default-0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see logs streaming in, you know it's working. The Services both have ClusterIPs and you get credentials generated automatically.&lt;/p&gt;

&lt;p&gt;First, open up another terminal window, there you expose the &lt;code&gt;quickstart-es-http&lt;/code&gt; service, so you can access it from your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward service/elasticsearch-es-http 9200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A default user named elastic is automatically created with the password stored in a Kubernetes secret. Back in your initial terminal window, run this command to retrieve the password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret elasticsearch-es-elastic-user &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.elastic}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use curl to test the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"elastic:&lt;/span&gt;&lt;span class="nv"&gt;$PASSWORD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-k&lt;/span&gt; &lt;span class="s2"&gt;"https://localhost:9200"&lt;/span&gt;
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
&lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="s2"&gt;"name"&lt;/span&gt; : &lt;span class="s2"&gt;"elasticsearch-es-default-0"&lt;/span&gt;,
   &lt;span class="s2"&gt;"cluster_name"&lt;/span&gt; : &lt;span class="s2"&gt;"elasticsearch"&lt;/span&gt;,
   &lt;span class="s2"&gt;"cluster_uuid"&lt;/span&gt; : &lt;span class="s2"&gt;"7auDvcXLTwqLmXfBcAXIqg"&lt;/span&gt;,
   &lt;span class="s2"&gt;"version"&lt;/span&gt; : &lt;span class="o"&gt;{&lt;/span&gt;
       &lt;span class="s2"&gt;"number"&lt;/span&gt; : &lt;span class="s2"&gt;"7.5.2"&lt;/span&gt;,
       &lt;span class="s2"&gt;"build_flavor"&lt;/span&gt; : &lt;span class="s2"&gt;"default"&lt;/span&gt;,
       &lt;span class="s2"&gt;"build_type"&lt;/span&gt; : &lt;span class="s2"&gt;"docker"&lt;/span&gt;,
       &lt;span class="s2"&gt;"build_hash"&lt;/span&gt; : &lt;span class="s2"&gt;"8bec50e1e0ad29dad5653712cf3bb580cd1afcdf"&lt;/span&gt;,
       &lt;span class="s2"&gt;"build_date"&lt;/span&gt; : &lt;span class="s2"&gt;"2020-01-15T12:11:52.313576Z"&lt;/span&gt;,
       &lt;span class="s2"&gt;"build_snapshot"&lt;/span&gt; : &lt;span class="nb"&gt;false&lt;/span&gt;,
       &lt;span class="s2"&gt;"lucene_version"&lt;/span&gt; : &lt;span class="s2"&gt;"8.3.0"&lt;/span&gt;,
       &lt;span class="s2"&gt;"minimum_wire_compatibility_version"&lt;/span&gt; : &lt;span class="s2"&gt;"6.8.0"&lt;/span&gt;,
       &lt;span class="s2"&gt;"minimum_index_compatibility_version"&lt;/span&gt; : &lt;span class="s2"&gt;"6.0.0-beta1"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
   &lt;span class="s2"&gt;"tagline"&lt;/span&gt; : &lt;span class="s2"&gt;"You Know, for Search"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hey presto! It works. This might be good for starters, but the cluster only has one Pod. Let's spice things up a bit and add a few more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfvojycl0ugxebvbcx22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfvojycl0ugxebvbcx22.png" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade and Configure the Elasticsearch Cluster
&lt;/h2&gt;

&lt;p&gt;Any edits you do to the configuration will automatically upgrade the cluster. The Operator will try to update all the configuration changes you tell it, except for existing volume claims, these cannot be resized. Make sure your Kubernetes cluster has enough resources to handle any resizing you do.&lt;/p&gt;

&lt;p&gt;If you want to have 3 Pods, run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: elasticsearch
spec:
version: 7.5.2
nodeSets:
 - name: default
  count: 3
  config:
     node.master: true
     node.data: true
     node.ingest: true
     node.store.allow_mmap: false
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will bump up the Pod count. Check out&lt;a href="https://github.com/elastic/cloud-on-k8s/blob/master/config/samples/elasticsearch/elasticsearch.yaml" rel="noopener noreferrer"&gt; this sample&lt;/a&gt; to see all the configuration options. Let's check if our Pods have updated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get all
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                             READY   STATUS   RESTARTS   AGE
pod/elasticsearch-es-default-0   1/1     Running   0         25m
pod/elasticsearch-es-default-1   1/1     Running   0         3m8s
pod/elasticsearch-es-default-2   1/1     Running   0         2m46s
​
NAME                               TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
service/elasticsearch-es-default   ClusterIP   None           &amp;lt;none&amp;gt;       &amp;lt;none&amp;gt;     25m
service/elasticsearch-es-http     ClusterIP   10.96.192.180   &amp;lt;none&amp;gt;        9200/TCP   25m
service/kubernetes                 ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP   2d2h
​
NAME                                       READY   AGE
statefulset.apps/elasticsearch-es-default   3/3     25m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Awesome! Our cluster is starting to look nice! This cluster that you deployed by default only allocates a persistent volume of 1 GB for storage using the default&lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/" rel="noopener noreferrer"&gt; storage class&lt;/a&gt; defined for the Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;Here's a sample of what adding more storage looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
  name: elasticsearch
spec:
  version: 7.5.2
  nodeSets:
  - name: default
    count: 3
    config:
      node.master: true
      node.data: true
      node.ingest: true
      node.store.allow_mmap: false
    volumeClaimTemplates:
    - metadata:
        name: elasticsearch-data
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: 4Gi
        storageClassName: standard
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll most likely want to have more control over this for production workloads. Check out the&lt;a href="https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-volume-claim-templates.html" rel="noopener noreferrer"&gt; Volume claim templates&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Run and Deploy Kibana with the Elasticsearch Operator
&lt;/h2&gt;

&lt;p&gt;This Operator is called ECK for a reason. It comes packaged with Kibana. In one of the sections above we ran this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get crd

&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                                           CREATED AT
apmservers.apm.k8s.elastic.co                  2020-02-05T15:46:33Z
elasticsearches.elasticsearch.k8s.elastic.co   2020-02-05T15:46:33Z
kibanas.kibana.k8s.elastic.co                  2020-02-05T15:46:33Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check it out. You have a &lt;code&gt;kibana.k8s.elastic.co/v1&lt;/code&gt; API as well. This is what you'll use to create your Kibana instance.&lt;/p&gt;

&lt;p&gt;Go ahead and specify a Kibana instance and reference your Elasticsearch cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: elasticsearch
spec:
  version: 7.5.2
  count: 1
  elasticsearchRef:
    name: elasticsearch
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a second to spin up the Pod. Similar to Elasticsearch, you can retrieve details about Kibana instances with this simple command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get kibana
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME           HEALTH   NODES   VERSION   AGE
elasticsearch   green    1       7.5.2     2m31s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait until the health is green, then check the Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pod &lt;span class="nt"&gt;--selector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kibana.k8s.elastic.co/name=elasticsearch'&lt;/span&gt;
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                               READY   STATUS   RESTARTS   AGE
elasticsearch-kb-5f568dcdb6-xd55w   1/1     Running   0         3m19s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Pods are up and running as well, you can go ahead and set up accessing Kibana. A ClusterIP Service is automatically created for Kibana:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get service elasticsearch-kb-http
​
&lt;span class="o"&gt;[&lt;/span&gt;Output]
NAME                   TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
elasticsearch-kb-http   ClusterIP   10.96.199.44   &amp;lt;none&amp;gt;        5601/TCP   4m24s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again, open up another terminal window, and use &lt;code&gt;kubectl port-forward&lt;/code&gt; to access Kibana from your local machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward service/elasticsearch-kb-http 5601
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;https://localhost:5601&lt;/code&gt; in your browser. Log in as the elastic user. Get the password with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secret elasticsearch-es-elastic-user &lt;span class="nt"&gt;-o&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.elastic}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you're signed in, you'll see the Kibana quickstart screen.&lt;/p&gt;

&lt;p&gt;There you have it. You've added a Kibana instance to your Kubernetes cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning Up and Deleting the Elasticsearch Operator
&lt;/h2&gt;

&lt;p&gt;With all resources installed and working, you should see this when running &lt;code&gt;kubectl&lt;/code&gt; get all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                                   READY   STATUS   RESTARTS   AGE
pod/elasticsearch-es-default-0          1/1     Running   0         13m
pod/elasticsearch-kb-5f568dcdb6-xd55w   1/1     Running   0         11m
​
NAME                               TYPE       CLUSTER-IP     EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;   AGE
service/elasticsearch-es-default   ClusterIP   None           &amp;lt;none&amp;gt;       &amp;lt;none&amp;gt;     13m
service/elasticsearch-es-http     ClusterIP   10.96.168.225   &amp;lt;none&amp;gt;        9200/TCP   13m
service/elasticsearch-kb-http     ClusterIP   10.96.199.44   &amp;lt;none&amp;gt;        5601/TCP   11m
service/kubernetes                 ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP   2d3h
​
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/elasticsearch-kb   1/1     1            1           11m
​
NAME                                         DESIRED   CURRENT   READY   AGE
replicaset.apps/elasticsearch-kb-5f568dcdb6   1         1         1       11m
​
NAME                                       READY   AGE
statefulset.apps/elasticsearch-es-default   1/1     13m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Way to go, you've configured an Elasticsearch cluster with Kibana using the Elasticsearch Operator! But, what if you need to delete resources? Easy. Run two commands and you're done.&lt;/p&gt;

&lt;p&gt;First, delete all Elastic resources from all namespaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete elastic &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--all-namespaces&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, delete the Operator itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete &lt;span class="nt"&gt;-f&lt;/span&gt; https://download.elastic.co/downloads/eck/1.0.0/all-in-one.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it, all clean!&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts About the Elasticsearch Operator
&lt;/h2&gt;

&lt;p&gt;In this tutorial you've learned about the Kubernetes Operator pattern, and how to run and deploy the Elasticsearch Operator on a Kubernetes cluster. You've also scaled up the number of Elasticsearch Pods on the cluster, and installed Kibana.&lt;/p&gt;

&lt;p&gt;With this knowledge on top of what you learned in part 1 of this series, you can make a decision whether to use a Helm chart with StatefulSets or the Elasticsearch Operator.&lt;/p&gt;

&lt;p&gt;Why bother learning Operators?&lt;/p&gt;

&lt;p&gt;In the last year we've witnessed a huge increase in popularity for the Operator Pattern. Right now, the official Elasticsearch Operator has the same number of stars on GitHub as the most popular Elasticsearch Helm chart. This popularity will seemingly continue to grow.&lt;/p&gt;

&lt;p&gt;What can you do now? Contribute! Learn even more about&lt;a href="https://sematext.com/kubernetes/" rel="noopener noreferrer"&gt; Kubernetes&lt;/a&gt;, and give back to the community. These projects are open-source for a reason. Help them grow!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hope you guys and girls enjoyed reading this as much as I enjoyed writing it. If you liked it, feel free to hit the share button so more people will see this tutorial. Until next time, be curious and have fun.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>elasticsearch</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A Step-by-Step Guide to Java Garbage Collection Tuning</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Mon, 27 Jan 2020 11:19:14 +0000</pubDate>
      <link>https://dev.to/sematext/a-step-by-step-guide-to-java-garbage-collection-tuning-2m1g</link>
      <guid>https://dev.to/sematext/a-step-by-step-guide-to-java-garbage-collection-tuning-2m1g</guid>
      <description>&lt;p&gt;Working with Java applications has a lot of benefits. Especially when compared to languages like C/C++. In the majority of cases, you get interoperability between operating systems and various environments. You can move your applications from server to server, from operating system to operating system, without major effort or in rare cases with minor changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8hdcejqb83zru5a0s6cr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8hdcejqb83zru5a0s6cr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the most interesting benefits of running a JVM based application is automatic memory handling. When you create an object in your code it is assigned on a heap and stays there until it is referenced from the code. When it is no longer needed it needs to be removed from the memory to make room for new objects. In programming languages like C or C++, the cleaning of the memory is done by us, programmers, manually in the code. In languages like Java or Kotlin, we don’t need to take care of that – it is done automatically by the JVM, by its garbage collector.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Is Garbage Collection Tuning?
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Garbage Collection GC tuning&lt;/strong&gt; is the process of adjusting the startup parameters of your JVM-based application to match the desired results. Nothing more and nothing less. It can be as simple as adjusting the heap size – the &lt;em&gt;-Xmx&lt;/em&gt; and &lt;em&gt;-Xms&lt;/em&gt; parameters. Which is by the way what you should start with. Or it can be as complicated as tuning all the advanced parameters to adjust the different heap regions. Everything depends on the situation and your needs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Is Garbage Collection Tuning Important?
&lt;/h1&gt;

&lt;p&gt;Cleaning our applications’ JVM process heap memory is not free. There are resources that need to be designated for the garbage collector so it can do its work. You can imagine that instead of handling the business logic of our application the CPU can be busy handling the removal of unused data from the heap.&lt;/p&gt;

&lt;p&gt;This is why it’s crucial for the garbage collector to work as efficiently as possible. The GC process can be heavy. During our work as developers and consultants, we’ve seen situations where the garbage collector was working for 20 seconds during a 60-second window of time. Meaning that 33% of the time the application was not doing its job — it was doing the housekeeping instead.&lt;/p&gt;

&lt;p&gt;We can expect threads to be stopped for very short periods of time. It happens constantly:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

2019-10-29T10:00:28.879-0100: 0.488: Total time for which application threads were stopped: 0.0001006 seconds, Stopping threads took: 0.0000065 seconds


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What’s dangerous, however, is a complete stop of the application threads for a very long period of time – like seconds or in extreme cases even minutes. This can lead to your users not being able to properly use your application at all. Your distributed systems can collapse because of elements not responding in a timely manner.&lt;/p&gt;

&lt;p&gt;To avoid that we need to ensure that the garbage collector that is running for our JVM applications is well configured and is doing its job as good as it can.&lt;/p&gt;

&lt;h1&gt;
  
  
  When to Do Garbage Collection Tuning?
&lt;/h1&gt;

&lt;p&gt;The first thing that you should know is that tuning the garbage collection should be one of the last operations you do. Unless you are absolutely sure that the problem lies in the garbage collection, don’t start with &lt;a href="https://sematext.com/blog/jvm-performance-tuning/" rel="noopener noreferrer"&gt;changing JVM options&lt;/a&gt;. To be blunt, there are numerous situations where the way how the garbage collector works only highlights a bigger problem.&lt;/p&gt;

&lt;p&gt;If your JVM memory utilization looks good and your garbage collector works without causing trouble, you shouldn’t spend time turning your garbage collection. You will most likely be more effective in refactoring the code to be more efficient.&lt;/p&gt;

&lt;p&gt;So how do we say that the garbage collector does a good job? We can look into our monitoring, like our own &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;. It will provide you information regarding your JVM memory utilization, the garbage collector work and of course the overall performance of your application. For example, have a look at the following chart:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fem36no6hhprzorlmjcmo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fem36no6hhprzorlmjcmo.png" alt="JVM Pool Size"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this chart, you can see something called “shark tooth”. Usually, it is a sign of a healthy JVM heap. The largest portion of the memory, called the old generation, gets filled up and then is cleared by the garbage collector. If we would correlate that with the garbage collector timings we would see the whole picture. Knowing all of that we can judge if we are satisfied with how the garbage collection is working or if tuning is needed.&lt;/p&gt;

&lt;p&gt;Another thing you can look into is garbage collection logs that we discussed in the &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;Understanding Java GC Logs&lt;/a&gt; blog post. You can also use tools like jstat or any &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;profiler&lt;/a&gt;. They will give you detailed information regarding what’s happening inside your JVM, especially when it comes to heap memory and garbage collection.&lt;/p&gt;

&lt;p&gt;There is also one more thing that you should consider when thinking about garbage collection performance tuning. The default Java garbage collection settings may not be perfect for your application, so to speak. Meaning, instead of going for more hardware or for more beefy machines you may want to look into how your memory is managed. Sometimes tuning can decrease the operation cost lowering your expenses and allowing for growth without growing the environment.&lt;/p&gt;

&lt;p&gt;Once you are sure that the garbage collector is to blame and you want to start optimizing its parameters we can start working on the JVM startup parameters.&lt;/p&gt;

&lt;h1&gt;
  
  
  Garbage Collection Tuning Procedure: How to Tune Java GC
&lt;/h1&gt;

&lt;p&gt;When talking about the procedure you should take when tuning the garbage collector you have to remember that there are more garbage collectors available in the JVM world. When dealing with smaller heaps and older JVM versions, like version 7, 8 or 9, you will probably use the good, old Concurrent Mark Sweep garbage collector for your old generation heap. With a newer version of the JVM, like 11, you are probably using G1GC. If you like experimenting you are probably using the newest JVM version along with ZGC. You have to remember that each garbage collector works differently. Hence, the tuning procedure for them will be different.&lt;/p&gt;

&lt;p&gt;Running a JVM based application with different garbage collectors is one thing, doing experiments is another. Java garbage collection tuning will require lots of experiments and tries. It’s normal that you won’t achieve the desired results in your first try. You will want to introduce changes one by one and observe how your application and the garbage collector behaves after each change.&lt;/p&gt;

&lt;p&gt;Whatever your motivation for GC tuning is I would like to make one thing clear. To be able to tune the garbage collector, you need to be able to see how it works. This means that you need to have visibility into GC metric or GC logs, or both, which would be the best solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting GC Tuning
&lt;/h2&gt;

&lt;p&gt;Start by looking at how your application behaves, what events fill up the memory space, and what space is filled. Remember that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assigned objects in the Eden generation are moved to Survivor space&lt;/li&gt;
&lt;li&gt;Assigned objects in the Survivor space are moved to Tenured generation if the counter is high enough or the counter is increased.&lt;/li&gt;
&lt;li&gt;Assigned objects in the Tenured generation are ignored and will not be collected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need to be sure you understand what is happening inside your application’s heap, and keep in mind what causes the garbage collection events. That will help you understand your application’s memory needs and how to improve garbage collection.&lt;/p&gt;

&lt;p&gt;Let’s start tuning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heap Size
&lt;/h2&gt;

&lt;p&gt;You would be surprised how often setting the correct heap size is overlooked. As consultants, we’ve seen a few of those, believe us. Start by checking if your heap size is really well set up.&lt;/p&gt;

&lt;p&gt;What should you consider when setting up the heap for your application? It depends on many factors of course. There are systems like Apache Solr or Elasticsearch which are heavily I/O dependent and can share the operating system file system cache. In such cases, you should leave as much memory as you can for the operating system, especially if your data is large. If your application processes a lot of data or does a lot of parsing, larger heaps may be needed.&lt;/p&gt;

&lt;p&gt;Anyways, you should remember that until &lt;strong&gt;32GB&lt;/strong&gt; of heap size you benefit from so-called &lt;strong&gt;compressed ordinary object pointers&lt;/strong&gt;. &lt;strong&gt;Ordinary object pointers&lt;/strong&gt; or OOP are 64-bits pointers to memory. They point to memory allowing the JVM to reference objects on the heap. At least this is how it works without getting deep into the internals.&lt;/p&gt;

&lt;p&gt;Up to 32GB of the heap size, JVM can compress those OOPs and thus save memory. This is how you can imagine the compressed ordinary object pointer in the JVM world:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj8k29g42gwor0i8v65ax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fj8k29g42gwor0i8v65ax.png" alt="Compressed OOPs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first 32 bits are used for the actual memory reference and are stored on the heap. 32 bits is enough to address every object on heaps up to 32GB. How do we calculate that? We have 232  – our space that can be addressed by a 32-bits pointer. Because of the three zeros in the tail of our pointer we have 232+3, which gives us 235, so 32GB of memory space that can be addressed. That’s the maximum heap size we can use with compressed ordinary object pointers.&lt;/p&gt;

&lt;p&gt;Going above &lt;strong&gt;32GB&lt;/strong&gt; of the heap will result in JVM using &lt;strong&gt;64-bits pointers&lt;/strong&gt;. In some cases going from 32GB to 35GB heap, you are likely to have more or less the same amount of usable space. That depends on your application memory usage, but you need to take that into consideration and probably go above 35GB to see the difference.&lt;/p&gt;

&lt;p&gt;Finally, how do I choose the proper heap size? Well, monitor your usage and see how your heap behaves. You can use your monitoring for that, like our &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt; and its &lt;a href="https://sematext.com/java-monitoring/" rel="noopener noreferrer"&gt;JVM monitoring&lt;/a&gt; capabilities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv0mptr310gykd9wnl8ez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fv0mptr310gykd9wnl8ez.png" alt="JVM Pool Size"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fol2as4p63ttw17c5hcfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fol2as4p63ttw17c5hcfx.png" alt="GC Collectors Summary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the JVM pool size and the GC summary charts. As you can see the JVM heap size can be characterized as shark teeth – a healthy pattern. Based on the first chart we can that we need at least 500 – 600MB of memory for that application. The point where the memory is evacuated is around 1.2GB of the total heap size, for the G1 garbage collector, in this case. In this scenario, we have the garbage collector running for about 2 seconds in the 60 seconds time period, which means that the JVM spends around 2% of the time in garbage collection. This is good and healthy.&lt;/p&gt;

&lt;p&gt;We can also look at the average garbage collection time along with the 99th and 90th percentile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuuj6mv6kc120s04kkzqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuuj6mv6kc120s04kkzqo.png" alt="GC Collectors Time"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on that information we can see that we don’t need a higher heap. Garbage collection is fast and efficiently clears the data.&lt;/p&gt;

&lt;p&gt;On the other hand, if we know that our application is used and processes data, its heap is above 70 – 80% of the maximum heap that we set it to and we would see GC struggling we know that we are in trouble. For example, look at this application’s memory pools:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi8neeztdvtfpdtqgmgiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fi8neeztdvtfpdtqgmgiu.png" alt="JVM Pool Size and Utilization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that something started happening and that memory usage is constantly above 80% in the &lt;strong&gt;old generation&lt;/strong&gt; space. Correlate that with garbage collector work:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fssifd6mcdv4f55rz5z5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fssifd6mcdv4f55rz5z5p.png" alt="GC Summary"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can clearly see signs of high memory utilization. The garbage collector started doing more work while memory is not being cleared. That means that even though JVM is trying to clear the data – it can’t. This is a sign of trouble coming – we just don’t have enough space on the heap for new objects. But keep in mind this may also be a sign of memory leaks in the application. If you see memory growth over time and garbage collection not being able to free the memory you may be hitting an issue with the application itself. Something worth checking.&lt;/p&gt;

&lt;p&gt;So how do we set the heap size? By setting its minimum and maximum size. The minimum size is set using the &lt;em&gt;-Xms&lt;/em&gt; JVM parameter and the maximum size is set using the &lt;em&gt;-Xmx&lt;/em&gt; parameter. For example, to set the heap size for our application to be of size &lt;strong&gt;2GB&lt;/strong&gt; we would add &lt;strong&gt;-Xms2g -Xmx2g&lt;/strong&gt; to our application startup parameters. In most cases, I would also set them to the same value to avoid heap resizing and in addition to that I would add the &lt;strong&gt;-XX:+AlwaysPreTouch&lt;/strong&gt; flag as well to load the memory pages into memory at the start of the application.&lt;/p&gt;

&lt;p&gt;We can also control the size of the young generation heap space by using the &lt;em&gt;-Xmn&lt;/em&gt; property, just like the &lt;em&gt;-Xms&lt;/em&gt; and &lt;em&gt;-Xmx&lt;/em&gt;. This allows us to explicitly define the size of the young generation heap space when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serial Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The Serial Garbage Collector is the simplest, single-threaded garbage collector. You can &lt;strong&gt;turn on&lt;/strong&gt; the &lt;strong&gt;Serial&lt;/strong&gt; garbage collector by adding the &lt;strong&gt;-XX:+UseSerialGC&lt;/strong&gt; flag to your JVM application startup parameters. We won’t focus on tuning the serial garbage collector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The Parallel garbage collector similar in its roots to the Serial garbage collector but uses multiple threads to perform garbage collection on your application heap. You can turn on the Parallel garbage collector by adding the &lt;strong&gt;-XX:+UseParallelGC&lt;/strong&gt; flag to your JVM application startup parameters. To disable it entirely, use the &lt;strong&gt;-XX:-UseParallelGC&lt;/strong&gt; flag.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning the Parallel Garbage Collector
&lt;/h3&gt;

&lt;p&gt;As we’ve mentioned The Parallel garbage collector &lt;strong&gt;uses multiple threads&lt;/strong&gt; to perform its cleaning duties. The &lt;strong&gt;number of threads&lt;/strong&gt; that the garbage collector can use is set by using the &lt;strong&gt;-XX:ParallelGCThreads&lt;/strong&gt; flag added to our application startup parameters.&lt;/p&gt;

&lt;p&gt;For example, if we would like 4 threads to do the garbage collection, we would add the following flag to our application parameters: &lt;strong&gt;-XX:ParallelGCThreads=4&lt;/strong&gt;. Keep in mind that the more threads you dedicate to cleaning duties the faster it can get. But there is also a downside of having more garbage collection threads. Each GC thread involved in a minor garbage collection event will reserve a portion of the tenured generation heap for promotions. This will create divisions of space and fragmentation. The more the threads the higher the fragmentation. Reducing the number of Parallel garbage collection threads and increasing the size of the old generation will help with the fragmentation if that becomes an issue.&lt;/p&gt;

&lt;p&gt;The second option that can be used is &lt;strong&gt;-XX:MaxGCPauseMillis&lt;/strong&gt;. It specifies the &lt;strong&gt;maximum pause time goal&lt;/strong&gt; between two consecutive garbage collection events. It is defined in milliseconds. For example, with a flag &lt;strong&gt;-XX:MaxGCPauseMillis=100&lt;/strong&gt; we tell the Parallel garbage collector that we would like to have the maximum pause of 100 milliseconds between garbage collections. The longer the gap between garbage collections the more garbage can be left on the heap making the next garbage collection more expensive. On the other hand, if the value is too small, the application will spend the majority of its time in garbage collection instead of executing business logic.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;maximum throughput target&lt;/strong&gt; can be set by using the &lt;strong&gt;-XX:GCTimeRatio&lt;/strong&gt; flag. It defines the &lt;strong&gt;ratio&lt;/strong&gt; between the &lt;strong&gt;time spent in GC&lt;/strong&gt; and the &lt;strong&gt;time spent outside of GC&lt;/strong&gt;. It is defined as &lt;em&gt;1/(1 + GC_TIME_RATIO_VALUE)&lt;/em&gt; and it’s a percentage of time spent in garbage collection.&lt;/p&gt;

&lt;p&gt;For example, setting &lt;strong&gt;-XX:GCTimeRatio=9&lt;/strong&gt; means that 10% of the application’s working time may be spent in the garbage collection. This means that the application should get 9 times more working time compared to the time given to garbage collection.&lt;/p&gt;

&lt;p&gt;By default, the value of &lt;strong&gt;-XX:GCTimeRatio&lt;/strong&gt; flag is set to 99 by the JVM, which means that the application will get 99 times more working time compared to the garbage collection which is a good trade-off for the server-side applications.&lt;/p&gt;

&lt;p&gt;You can also control the adjustment of the generations of the Parallel garbage collector. The goals for the Parallel garbage collector are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;achieve maximum pause time&lt;/li&gt;
&lt;li&gt;achieve throughput, only if pause time is achieved&lt;/li&gt;
&lt;li&gt;achieve footprint only if the first two goals are achieved&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Parallel garbage collector grows and shrinks the generations to achieve the goals above. Growing and shrinking the generations is done in increments at a fixed percentage. By default, the generation grows in increments of 20% and shrinks in increments of 5%. Each generation is configured on its own. The percentage of the growth of a generation is controlled by the &lt;strong&gt;-XX:YoungGenerationSizeIncrement&lt;/strong&gt; flag. The growth of the old generation is controlled by the &lt;strong&gt;-XX:TenuredGenerationSizeIncrement&lt;/strong&gt; flag.&lt;/p&gt;

&lt;p&gt;The shrinking part can be controlled by the &lt;strong&gt;-XX:AdaptiveSizeDecrementScaleFactor&lt;/strong&gt; flag. For example, the percentage of the shrinking increment for the young generation is set by dividing the value of &lt;strong&gt;-XX:YoungGenerationSizeIncrement&lt;/strong&gt; flag by the value of the &lt;strong&gt;-XX:AdaptiveSizeDecrementScaleFactor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the pause time goal is not achieved the generations will be shrunk one at the time. If the pause time of both generations is above the goal, the generation that caused threads to stop for a longer period of time will be shrunk first. If the throughput goal is not met then both the young and old generations will be grown.&lt;/p&gt;

&lt;p&gt;The Parallel garbage collector can throw &lt;strong&gt;OutOfMemory&lt;/strong&gt; exception if too much time is spent in garbage collection. By default, if more than 98% of the time is spent in garbage collection and less than 2% of the heap is recovered such exception will be thrown. If we want to disable that behavior we can add the &lt;strong&gt;-XX:-UseGCOverheadLimit&lt;/strong&gt; flag. But please be aware that garbage collectors working for an extensive amount of time and clearing very little or close to no memory at all usually means that your heap size is too low or your application suffers from memory leaks.&lt;/p&gt;

&lt;p&gt;Once you know all of this we can start looking at &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;garbage collector logs&lt;/a&gt;. They will tell us about the events that our Parallel garbage collector performs. That should give us the basic idea of where to start the tuning and which part of the heap is not healthy or could use some improvements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrent Mark Sweep Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The Concurrent Mark Sweep garbage collector, a mostly concurrent implementation that shares the threads used for garbage collection with the application. You can turn it on by adding the &lt;strong&gt;-XX:+UseConcMarkSweepGC&lt;/strong&gt; flag to your JVM application startup parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning the Concurrent Mark Sweep Garbage Collector
&lt;/h3&gt;

&lt;p&gt;Similar to other available collectors in the JVM world the CMS garbage collector is generational which means that you can expect two types of events to happen – minor and major collections. The idea here is that most work will be done in parallel to the application threads to prevent the tenured generation to get full. During normal work, most of the garbage collection is done without stopping application threads. CMS only stops the threads for a very short period of time at the beginning and the middle of the collection during the major collection. Minor collections are done in a very similar way to how the Parallel garbage collector works – all application threads are stopped during GC.&lt;/p&gt;

&lt;p&gt;One of the signals that your CMS garbage collector needs tuning is &lt;strong&gt;concurrent mode failures&lt;/strong&gt;. This indicates that the Concurrent Mark Sweep garbage collector was not able to reclaim all unreachable objects before the old generation filled up or there was simply not enough fragmented space in the heap tenured generation to promote objects.&lt;/p&gt;

&lt;p&gt;But what about the concurrency we’ve mentioned? Let’s get back to the pauses for a while. During the concurrent phase, the CMS garbage collector pauses two times. The first is called the &lt;strong&gt;initial mark pause&lt;/strong&gt;. It is used to mark the live objects that are directly reachable from the roots and from any other place in the heap. The second pause called &lt;strong&gt;remark pause&lt;/strong&gt; is done at the end of the concurrent tracing phase. It finds objects that were missed during the initial mark pause, mainly because of being updated in the meantime. The concurrent tracing phase is done between those two pauses. During this phase, one or more garbage collector threads may be working to clear the garbage. After the whole cycle ends the Concurrent Mark Sweep garbage collector waits until the next cycle while consuming close to no resources. However, be aware that during the concurrent phase your application may experience performance degradation.&lt;/p&gt;

&lt;p&gt;The collection of &lt;strong&gt;tenured generation space&lt;/strong&gt; must be &lt;strong&gt;timed&lt;/strong&gt; when using the CMS garbage collector. Because &lt;strong&gt;concurrent mode failures&lt;/strong&gt; can be &lt;strong&gt;expensive&lt;/strong&gt; we need to properly &lt;strong&gt;adjust&lt;/strong&gt; the &lt;strong&gt;start&lt;/strong&gt; of the &lt;strong&gt;old generation&lt;/strong&gt; heap &lt;strong&gt;cleaning&lt;/strong&gt; not to hit such events. We can do that by using the &lt;strong&gt;-XX:CMSInitiatingOccupancyFraction&lt;/strong&gt; flag. It is used to set the &lt;strong&gt;percentage&lt;/strong&gt; of the &lt;strong&gt;old generation&lt;/strong&gt; heap utilization when the CMS should &lt;strong&gt;start clearing&lt;/strong&gt; it. For example, starting at 75% we would set the mentioned flag to &lt;strong&gt;-XX:CMSInitiatingOccupancyFraction=75&lt;/strong&gt;. Of course, this is only an informative value and the garbage collector will still use heuristics and try to determine the best possible value for starting its old generation cleaning job. To avoid using heuristics we can use the &lt;strong&gt;-XX:+UseCMSInitiatingOccupancyOnly&lt;/strong&gt; flag. That way we will only stick to the percentage from the &lt;strong&gt;-XX:CMSInitiatingOccupancyFraction&lt;/strong&gt; setting.&lt;/p&gt;

&lt;p&gt;So when setting the &lt;strong&gt;-XX:+UseCMSInitiatingOccupancyOnly&lt;/strong&gt; flag to a higher value you delay the cleaning of the old generation space on the heap. This means that your application will run longer without the need for CMS kicking in to clear the tenured space. But, when the process starts it may be more expensive because it will have more work. On the other hand, setting the &lt;strong&gt;-XX:+UseCMSInitiatingOccupancyOnly&lt;/strong&gt; flag to a lower value will make the CMS tenured generation cleaning more often, but it may be faster. Which one to choose – that depends on your application and needs to be adjusted per use case.&lt;/p&gt;

&lt;p&gt;We can also tell our garbage collector to collect the young generation heap during the remark pause or before doing the Full GC. The first is done by adding the &lt;strong&gt;-XX:+CMSScavengeBeforeRemark&lt;/strong&gt; flag to our startup parameters. The second is done by adding the &lt;strong&gt;-XX:+ScavengeBeforeFullGC&lt;/strong&gt; flag to our application startup parameters. As a result, it can improve garbage collection performance as it will not need to check for references between the young and old generation heap spaces.&lt;/p&gt;

&lt;p&gt;The remark phase of the Concurrent Mark Sweep garbage collector can potentially speed it up. By default it is a single-threaded and as you recall we’ve mentioned that it stops all the application threads. By including the &lt;strong&gt;-XX:+CMSParallelRemarkEnabled&lt;/strong&gt; flag to our application startup parameters, we can force the remark phase to use multiple threads. However, because of certain implementation details, it is not actually always true that the concurrent version of the remark phase will be faster compared to the single-threaded version. That’s something you have to check and test in your environment.&lt;/p&gt;

&lt;p&gt;Similar to the Parallel garbage collector, the Concurrent Mark Sweep garbage collector can throw &lt;strong&gt;OutOfMemory&lt;/strong&gt; exceptions if &lt;strong&gt;too much time&lt;/strong&gt; is spent in &lt;strong&gt;garbage collection&lt;/strong&gt;. By default, if more than 98% of the time is spent in garbage collection and less than 2% of the heap is recovered such an exception will be thrown. If we want to disable that behavior we can add the &lt;strong&gt;-XX:-UseGCOverheadLimit&lt;/strong&gt; flag. The difference compared to the Parallel garbage collector is that the &lt;strong&gt;time&lt;/strong&gt; that &lt;strong&gt;counts towards the 98%&lt;/strong&gt; is only counted when the &lt;strong&gt;application threads&lt;/strong&gt; are &lt;strong&gt;stopped&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  G1 Garbage Collector
&lt;/h2&gt;

&lt;p&gt;G1 garbage collector, the default garbage collector in the newest Java versions targeted for latency-sensitive applications. You can turn it on by adding the &lt;strong&gt;-XX:+G1GC&lt;/strong&gt; flag to your JVM application startup parameters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning G1 Garbage Collector
&lt;/h3&gt;

&lt;p&gt;There are also two things worth mentioning. The G1 garbage collector tries to perform longer operations in parallel without stopping the application threads. The quick operations will be performed faster when application threads are paused. So it’s yet another implementation of &lt;strong&gt;mostly concurrent&lt;/strong&gt; garbage collection algorithms.&lt;/p&gt;

&lt;p&gt;The G1 garbage collector cleans memory mostly in &lt;strong&gt;evacuation fashion&lt;/strong&gt;. Live objects from one memory area are copied to a new area and compacted along the way. After the process is done, the memory area from which the object was copied is again available for object allocation.&lt;/p&gt;

&lt;p&gt;On a very high level, the G1GC goes between two phases. The first phase is called &lt;strong&gt;young-only&lt;/strong&gt; and focuses on the young generation space. During that phase, the objects are moved gradually from the young generation to the old generation space. The second phase is called &lt;strong&gt;space reclamation&lt;/strong&gt; and is incrementally reclaiming the space in the old generation while also taking care of the young generation at the same time. Let’s look closer at those phases as there are some properties we can tune there.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;young-only phase&lt;/strong&gt; starts with a few young-generation collections that promote objects to the tenured generation. That phase is active until the old generation space reaches a certain threshold. By default, it’s 45% utilization and we can control that by setting the &lt;strong&gt;-XX:InitiatingHeapOccupancyPercent&lt;/strong&gt; flag and its value. Once that threshold is hit, G1 starts a different young generation collection, one called &lt;strong&gt;concurrent start&lt;/strong&gt;. The &lt;strong&gt;-XX:InitiatingHeapOccupancyPercent&lt;/strong&gt; flag which controls the &lt;strong&gt;Initial Mark&lt;/strong&gt; collection is the initial value that is further adjusted by the garbage collector. To turn off the adjustments add &lt;strong&gt;-XX:-G1UseAdaptiveIHOP&lt;/strong&gt; flag to your JVM startup parameters.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;concurrent start&lt;/strong&gt;, in addition to the normal young generation collection, starts the object marking process. It determines all live, reachable objects in the old generation space that need to be kept for the following space reclamation phase. To finish the marking process two additional steps are introduced – remark and cleanup. Both of them pause the application threads. The remark step performs global processing of references, class unloading, completely reclaims empty regions and cleans up internal data structures. The cleanup step determines if the space-reclamation phase is needed. If it’s needed the young-only phase is ended with Prepare Mixed young collection and the space-reclamation phase is launched.&lt;/p&gt;

&lt;p&gt;The space-reclamation phase contains multiple Mixed garbage collections that work on both young and old generation regions of the G1GC heap space. The space-reclamation phase ends when the G1GC sees that evacuating more old generation regions wouldn’t give enough free space to make the effort of reclaiming the space worthwhile. It can be set by using the &lt;strong&gt;-XX:G1HeapWastePercent&lt;/strong&gt; flag value.&lt;/p&gt;

&lt;p&gt;We can also control, at least to some degree, if the periodic garbage collection will run. By using the &lt;strong&gt;-XX:G1PeriodicGCSystemLoadThreshold&lt;/strong&gt; flag we can set the average load above which the periodic garbage collection will not be run. For example, if our system is load is 10 for the last minute and we set the &lt;strong&gt;-XX:G1PeriodicGCSystemLoadThreshold=10&lt;/strong&gt; flag, the period garbage collection will not be executed.&lt;/p&gt;

&lt;p&gt;The G1 garbage collector, apart from the &lt;em&gt;-Xmx&lt;/em&gt; and &lt;em&gt;-Xms&lt;/em&gt; flags, allows us to use a set of flags to size the heap and its regions. We can use the &lt;strong&gt;-XX:MinHeapFreeRatio&lt;/strong&gt; to tell the garbage collector the ratio of the free memory that should be achieved and the &lt;strong&gt;-XX:MaxHeapFreeRatio&lt;/strong&gt; flag to set the desired maximum ratio of the free memory on the heap. We also know that G1GC tries to keep the young generation size between the values of &lt;strong&gt;-XX:G1NewSizePercent&lt;/strong&gt; and &lt;strong&gt;-XX:G1MaxNewSizePercent&lt;/strong&gt;. That also determines the pause times. Decreasing the size may speed up the garbage collection process at the cost of less work. We can also set the strict size of the young generation by using the &lt;strong&gt;-XX:NewSize&lt;/strong&gt; and the &lt;strong&gt;-XX:MaxNewSize&lt;/strong&gt; flags.&lt;/p&gt;

&lt;p&gt;The documentation on tuning the G1 garbage collector says that we shouldn’t touch it in general. Eventually, we should only modify the desired pause times for different heap sizes. Fair enough. But, it’s also good to know what and how we can tune and how those properties affect the G1 garbage collector behavior.&lt;/p&gt;

&lt;p&gt;When &lt;strong&gt;tuning for&lt;/strong&gt; garbage collector &lt;strong&gt;latency&lt;/strong&gt; we should keep the pause time to a minimum. Meaning that in most cases the &lt;em&gt;-Xmx&lt;/em&gt; and &lt;em&gt;-Xms&lt;/em&gt; values should be set to the same value and we should also load the memory pages during application start by using the &lt;strong&gt;-XX:+AlwaysPreTouch&lt;/strong&gt; flag.&lt;/p&gt;

&lt;p&gt;If your young-only phase takes too long it’s a sign that decreasing the &lt;strong&gt;-XX:G1NewSizePercent&lt;/strong&gt; (defaults to 5) value is a good idea. In some cases decreasing the &lt;strong&gt;-XX:G1MaxNewSizePercent&lt;/strong&gt; (defaults to 60) can also help. If the Mixed collections take too long we are advised to increase the value of &lt;strong&gt;-XX:G1MixedGCCountTarget&lt;/strong&gt; flag to spread the tenured generation GC across more collections. Increase the &lt;strong&gt;-XX:G1HeapWastePercent&lt;/strong&gt; to stop the old generation garbage collection earlier. You can also change the &lt;strong&gt;-XX:G1MixedGCLiveThresholdPercent&lt;/strong&gt; – it defaults to 65 and controls the occupancy threshold above which the old generation heap will be included in the mixed collection. Increasing this value will tell garbage collection to omit less occupied old generation space regions when doing the mixed collection. Regions that have a lot of objects in them take a longer time to collect garbage from. By using the mentioned flag we can avoid setting these regions as candidates for garbage collection. If you’re seeing a high update and scan RS times, decreasing the &lt;strong&gt;-XX:G1RSetUpdatingPauseTimePercent&lt;/strong&gt; flag value, including the &lt;strong&gt;-XX:-ReduceInitialCardMarks&lt;/strong&gt; flag, and increasing the &lt;strong&gt;-XX:G1RSetRegionEntries&lt;/strong&gt; flag may help. There is also one additional flag, the &lt;strong&gt;-XX:MaxGCPauseTimeMillis&lt;/strong&gt; (defaults to 250) which defines the maximum, desired pause time. If you would like to reduce the pause time, lowering the value may help as well.&lt;/p&gt;

&lt;p&gt;When &lt;strong&gt;tuning for throughput&lt;/strong&gt; we want the garbage collector to clean as much garbage as possible. Mostly in cases of systems that process and hold a lot of data. The first thing that you should go for is increasing the &lt;strong&gt;-XX:MaxGCPauseMillis&lt;/strong&gt; value. By doing that we relax the garbage collector. This allows it to work longer to process more objects on the heap. However, that may not be enough. In such cases increasing the &lt;strong&gt;-XX:G1NewSizePercent&lt;/strong&gt; flag value should help. In some cases the throughput may be limited by the size of young generation regions – in such cases increasing the &lt;strong&gt;-XX:G1MaxNewSizePercent&lt;/strong&gt; flag value should help.&lt;/p&gt;

&lt;p&gt;We can also decrease the parallelism which requires a lot of work from the CPU. Using the &lt;strong&gt;-XX:G1RSetUpdatingPauseTimePercent&lt;/strong&gt; flag and increasing its value will allow more work when the application threads are paused and will decrease the time spent in concurrent parts of the phase. Also similar to latency tuning you may want to keep the -Xmx and -Xms flags to the same value to avoid heap resizing. Load the memory pages to memory by using the &lt;strong&gt;-XX:+AlwaysPreTouch&lt;/strong&gt; flag and the &lt;strong&gt;-XX:+UseLargePages&lt;/strong&gt; flag. But please remember to apply the changes one by one and compare the results so that you understand what is happening.&lt;/p&gt;

&lt;p&gt;Finally, we can &lt;strong&gt;tune&lt;/strong&gt; for &lt;strong&gt;heap size&lt;/strong&gt;. There is a single option that we can think about here, the &lt;strong&gt;-XX:GCTimeRatio&lt;/strong&gt; (defaults to 12). It determines the ratio of time spent in garbage collection compared to application threads doing their work and is calculated as &lt;em&gt;1/(1 + GCTimeRatio)&lt;/em&gt;. The default value will result in about 8% of the application working time to be spent in garbage collection, which is more than the Parallel GC. More time in garbage collection will allow clearing more space on the heap, but this is highly dependent on the application and it is hard to give general advice. Experiment to find the value that suits your needs.&lt;/p&gt;

&lt;p&gt;There are also general tunable parameters for the G1 garbage collector. We can control the degree of parallelization when using this garbage collector. By including the &lt;strong&gt;-XX:+ParallelRefProcEnabled&lt;/strong&gt; flag and changing the &lt;strong&gt;-XX:ReferencesPerThread&lt;/strong&gt; flag value. For each N references defined by the &lt;strong&gt;-XX:ReferencesPerThread&lt;/strong&gt; flag a single thread will be used. Setting this value to 0 will tell the G1 garbage collector to always use the number of threads specified by the &lt;strong&gt;-XX:ParallelGCThreads&lt;/strong&gt; flag value. For more parallelization decrease the &lt;strong&gt;-XX:ReferencesPerThread&lt;/strong&gt; flag value. This should speed up the parallel parts of the garbage collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Z Garbage Collector
&lt;/h2&gt;

&lt;p&gt;Still experimental, very scalable and low latency implementation. If you would like to experiment with that Z garbage collector you must use JDK 11 or newer and add the &lt;strong&gt;-XX:+UseZGC&lt;/strong&gt; flag to your application startup parameters along with the &lt;strong&gt;-XX:+UnlockExperimentalVMOptions&lt;/strong&gt; flag as the Z garbage collector is still considered experimental.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning the Z Garbage Collector
&lt;/h3&gt;

&lt;p&gt;There aren’t many parameters that we can play around with when it comes to the Z garbage collector. As the documentation states, the most important option here is the maximum heap size, so the -Xmx flag. Because the Z garbage collector is a concurrent collector, the heap size must be adjusted in a way that it can hold the live set of objects of your application and allows for the headroom to allow allocations while the garbage collector is running. This means that the heap size may need to be higher compared to other garbage collectors and the more memory you assign to the heap the better results you may expect from the garbage collector.&lt;/p&gt;

&lt;p&gt;The second option that you can expect is, of course, the number of threads that the Z garbage collector will use. After all, it is a concurrent collector, so it can utilize more than a single thread. We can set the number of threads that the Z garbage collector will use by using the &lt;strong&gt;-XX:ConcGCThreads&lt;/strong&gt; flag. The collector itself uses heuristics to choose the proper number of threads it should use, but as usual, it is highly dependent on the application and in some cases setting that number to a static value may bring better results. However, that needs to be tested as it is very use-case dependent. There are two things to remember though. If you assign too many threads for the garbage collector your application may not have enough computing power to do its job. Set the number of garbage collector threads to a low number and the garbage may not be collected fast enough. Take that into consideration when tuning.&lt;/p&gt;

&lt;h1&gt;
  
  
  Other JVM Options
&lt;/h1&gt;

&lt;p&gt;We’ve covered quite a lot when it comes to garbage collection parameters and how they affect garbage collection. But, not everything. There is way more to it than that. Of course, we won’t talk about every single parameter, it just doesn’t make sense. However, there are a few more things that you should know about.&lt;/p&gt;

&lt;h2&gt;
  
  
  JVM Statistics Causing Long Garbage Collection Pauses
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.evanjones.ca/jvm-mmap-pause.html" rel="noopener noreferrer"&gt;Some people&lt;/a&gt; reported that on Linux systems, during high I/O utilization the garbage collection can pause threads for a long period of time. This is probably caused by the JVM using a memory-mapped file called hsperfdata. That file is written in the /tmp directory and is used for keeping the statistics and safepoints. The mentioned file is updated during GC. On Linux, modifying a memory-mapped file can be blocked until I/O completes. As you can imagine such an operation can take a longer period of time, presumably hundreds of milliseconds.&lt;/p&gt;

&lt;p&gt;How to spot such an issue in your environment? You need to look into the timings of your garbage collection. If you see in the garbage collection logs that the real-time spent by the JVM for garbage collection is way longer than the user and system metrics combined you have a potential candidate. For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[Times: user=0.13 sys=0.11, real=5.45 secs]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If your system is heavily I/O based and you see the mentioned behavior you can move the path of your GC logs and the tmpfs to a fast SSD drive. With recent JDK versions, the temporary directory that Java uses is hardcoded, so we can’t use the &lt;strong&gt;-Djava.io.tmpdir&lt;/strong&gt; to change that. You can also include the &lt;strong&gt;-XX:+PerfDisableSharedMem&lt;/strong&gt; flag to your JVM application parameters. You need to be aware that including that option will break tools that are using the statistics from the hsperfdata file. For example, jstat will not work.&lt;/p&gt;

&lt;p&gt;You can read more on that issue in the blog post from the &lt;a href="https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic" rel="noopener noreferrer"&gt;Linkedin engineering&lt;/a&gt; team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heap Dump on Out Of Memory Exception
&lt;/h2&gt;

&lt;p&gt;One thing that can be very useful when dealing with Out Of Memory exceptions, diagnosing their cause and looking into problems like memory leaks are heap dumps. A heap dump is basically a file with the contents of the heap written on disk. We can generate heap dumps on demand, but it takes time and can freeze the application or, in the best-case scenario, make it slow. But if our application crashes we can’t grab the heap dump – it’s already gone.&lt;/p&gt;

&lt;p&gt;To avoid losing information that can help us in diagnosing problems we can instruct the JVM to create a heap dump when the OutOfMemory error happens. We do that by including the &lt;strong&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/strong&gt; flag. We can also specify where the heaps should be stored by using the &lt;strong&gt;-XX:HeapDumpPath&lt;/strong&gt; flag and setting its value to the location we want to write the heap dump to. For example: &lt;strong&gt;-XX:HeapDumpPath=/tmp/heapdump.hprof&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep in mind that the heap dump file may be very big – as large as your heap size. So you need to account for that when setting the path where the file should be written. We’ve seen situations where the JVM was not able to write the 64GB heap dump file on the target file system.&lt;/p&gt;

&lt;p&gt;For analysis of the file, there are tools that you can use. There are open-source tools like &lt;a href="https://www.eclipse.org/mat/" rel="noopener noreferrer"&gt;MAT&lt;/a&gt; and proprietary tools like &lt;a href="https://www.yourkit.com/" rel="noopener noreferrer"&gt;YourKit Java Profiler&lt;/a&gt; or &lt;a href="https://www.ej-technologies.com/products/jprofiler/overview.html" rel="noopener noreferrer"&gt;JProfiler&lt;/a&gt;. There are also services like &lt;a href="https://heaphero.io/" rel="noopener noreferrer"&gt;heaphero.io&lt;/a&gt; that can help you with the analysis, while older versions of the Oracle JDK distribution come with &lt;a href="https://docs.oracle.com/javase/7/docs/technotes/tools/share/jhat.html" rel="noopener noreferrer"&gt;jhat – the Java Heap Analysis Tool&lt;/a&gt;. Choose the one that you like and fit your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using -XX:+AggressiveOpts
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;-XX:+AgressiveOpts&lt;/strong&gt; flag turns on additional flags that are proven to result in an increase of performance during a set of benchmarks. Those flags can change from version to version and contain options like large autoboxing cache and removal of aggressive autoboxing. It also includes disabling of the biased locking delay. Should you use this flag? That depends on your use case and your production system. As usual, test in your environment, compare instances with and without the flag and see how large of a difference it makes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Tuning garbage collection is not an easy task. It requires knowledge and understanding. You need to know the garbage collector that you are working with and you need to understand your application’s memory needs. Every application is different and has different memory usage patterns, thus requires different garbage collection strategies. It’s also not a quick task. It will take time and resources to make improvements in iterations that will show you if you are going in the right direction with each and every change.&lt;/p&gt;

&lt;p&gt;Remember that we only touched the tip of the iceberg when it comes to tuning garbage collectors in the JVM world. We’ve only mentioned a limited number of available flags that you can turn on/off and adjust. For additional context and learning, I suggest going to &lt;a href="https://docs.oracle.com/en/java/javase/13/gctuning/" rel="noopener noreferrer"&gt;Oracle HotSpot VM Garbage Collection Tuning Guide&lt;/a&gt; and reading the parts that you think may be of interest to you. Look at your garbage collection logs, analyze them, try to understand them. It will help you in understanding your environment and what’s happening inside the JVM when garbage is collected. In addition to that, experiment a lot! Experiment in your test environment, on your developer machines, experiment in some of the production or pre-production instances and observe the difference in behavior.&lt;/p&gt;

&lt;p&gt;Hopefully, this article will help you on your journey to a healthy garbage collection in your JVM based applications. Good luck!&lt;/p&gt;

</description>
      <category>java</category>
      <category>gc</category>
      <category>tuning</category>
      <category>performance</category>
    </item>
    <item>
      <title>A Quick Start on Java Garbage Collection: What it is, and How it works</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Mon, 27 Jan 2020 10:43:26 +0000</pubDate>
      <link>https://dev.to/sematext/a-quick-start-on-java-garbage-collection-what-it-is-and-how-it-works-14d9</link>
      <guid>https://dev.to/sematext/a-quick-start-on-java-garbage-collection-what-it-is-and-how-it-works-14d9</guid>
      <description>&lt;p&gt;In this tutorial, we will talk about how different Java Garbage Collectors work and what you can expect from them. This will give us the necessary background to start tuning the garbage collection algorithm of your choice.&lt;/p&gt;

&lt;p&gt;Before going into Java Garbage Collection tuning we need to understand two things. First of all, how garbage collection works in theory and how it works in the system we are going to tune. Our system’s garbage collector work is described by garbage collector logs and metrics from observability tools like &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud for JVM&lt;/a&gt;. We talked about how to read and understand &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;Java Garbage Collection logs&lt;/a&gt; in a previous blog post.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Garbage Collection in Java: A Definition
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Java Garbage Collection&lt;/strong&gt; is an automatic process during which the Java Virtual Machine inspects the object on the heap, checks if they are still referenced and releases the memory used by those objects that are no longer needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Object Eligibility: When Does Java Perform Garbage Collection
&lt;/h1&gt;

&lt;p&gt;Let’s take a quick look on when the object is ready to be collected by the garbage collection and how to actually request the Java Virtual Machine to start garbage collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Make an Object Eligible for GC?
&lt;/h2&gt;

&lt;p&gt;To put it straight – you don’t have to do anything explicitly to make an object eligible for garbage collection. When an object is no longer used in your application code, the heap space used by it can be reclaimed. Look at the following Java code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;variableOne&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;variableTwo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;variableOne&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;variableTwo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;em&gt;run()&lt;/em&gt; method we explicitly create two variables. They are first put on the heap, in the young generation heap. Once the method finishes its execution they are no longer needed and they start being eligible for garbage collection. When a young generation garbage collection happens the memory used by those variables may be reclaimed. If that happens the previously occupied memory will be visible as free.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Request the JVM to Run GC?
&lt;/h2&gt;

&lt;p&gt;The best thing regarding Java garbage collection is that it is automatic. Until the time comes, and you want and need to control and tune it, you don’t have to do anything. When the Java Virtual Machine will decide it’s time to start reclaiming the space on the heap and throwing away unused objects it will just start the garbage collection process.&lt;/p&gt;

&lt;p&gt;If you want to force garbage collection you can use the System object from the java.lang package and its &lt;em&gt;gc()&lt;/em&gt; method or the &lt;em&gt;Runtime.getRuntime().gc()&lt;/em&gt; call. As the &lt;a href="https://docs.oracle.com/javase/9/docs/api/java/lang/System.html#gc--" rel="noopener noreferrer"&gt;documentation states&lt;/a&gt; – Java Virtual Machine will do its best efforts to reclaim the space. This means that the garbage collection may actually not happen, this depends on the JVM. If the garbage collection happens it will be a Major collection which means that we can expect a &lt;em&gt;stop-the-world&lt;/em&gt; event to happen. In general, using the &lt;em&gt;System.gc()&lt;/em&gt; is considered a bad practice and we should tune the work of the garbage collector instead of calling it explicitly.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Does Java Garbage Collection Work?
&lt;/h1&gt;

&lt;p&gt;No matter what implementation of the garbage collector we use, to clean up the memory, a short pause needs to happen. Those pauses are also called stop-the-world events or STW in short. You can envision your JVM-based application’s working cycles in the following way:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fggg9ftbcticb4bh5zbv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fggg9ftbcticb4bh5zbv5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step of the cycle starts when your application threads are started and your business code is working. This is where your application code is running. At a certain point in time, an event happens that triggers garbage collection. To clear the memory, application threads have to be stopped. This is where the work of your application stops and the next steps start. The garbage collector marks objects that are no longer used and reclaims the memory. Finally, an optional step of heap resizing may happen if possible. Then the circle starts again, application threads are started. The full cycle of the garbage collection is called the &lt;strong&gt;epoch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The key when running JVM applications and tuning the garbage collector is to keep the application threads running for as long as possible. That means that the pauses caused by the garbage collector should be minimal.&lt;/p&gt;

&lt;p&gt;The second thing that we need to talk about is generations. Java garbage collectors are generational, which means that they work under certain principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Young data will not survive long&lt;/li&gt;
&lt;li&gt;Data that is old will continue to persist in memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s why JVM heap memory is divided into generations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Young generation&lt;/strong&gt; which is divided into two sections called &lt;strong&gt;Eden space&lt;/strong&gt; and &lt;strong&gt;Survivor space&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Old generation, or &lt;strong&gt;Tenured space&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp3gez06rhvaclxfc70or.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp3gez06rhvaclxfc70or.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simplified promotion of objects between spaces and generations can be illustrated with the following example. When an object is created it is first put into the &lt;strong&gt;young generation&lt;/strong&gt; space into the &lt;strong&gt;Eden space&lt;/strong&gt;. Once the young garbage collection happens the object is promoted into the &lt;strong&gt;Survivor space 0&lt;/strong&gt; and next into the &lt;strong&gt;Survivor space 1&lt;/strong&gt;. If the object is still used at this point the next garbage collection cycle will move it to the &lt;strong&gt;Tenured space&lt;/strong&gt; which means that it is moved to the &lt;strong&gt;old generation&lt;/strong&gt;. You can imagine it as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwnaeh997aybve47dryvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwnaeh997aybve47dryvd.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the &lt;strong&gt;Eden&lt;/strong&gt; space contains newly created objects and is empty at the beginning of the &lt;strong&gt;epoch&lt;/strong&gt;. During the epoch, the &lt;strong&gt;Eden&lt;/strong&gt; space will fill up eventually triggering a &lt;strong&gt;Minor GC&lt;/strong&gt; event when filled up. The &lt;strong&gt;Survivor&lt;/strong&gt; spaces contain objects that were used during at least a single &lt;strong&gt;epoch&lt;/strong&gt;. Objects that survived through many &lt;strong&gt;epochs&lt;/strong&gt; will be eventually promoted to the &lt;strong&gt;Tenured&lt;/strong&gt; generation.&lt;/p&gt;

&lt;p&gt;Before Java 8 there was one additional memory space called the &lt;strong&gt;PermGen&lt;/strong&gt;. &lt;strong&gt;PermGen&lt;/strong&gt; or otherwise &lt;strong&gt;Permanent Generation&lt;/strong&gt; was a special space on the heap separated from its other parts – the young and the tenured generation. It was used to store metadata such as classes and methods.&lt;/p&gt;

&lt;p&gt;Starting from Java 8, the &lt;strong&gt;Metaspace&lt;/strong&gt; is the memory space that replaces the removed PermGen space. The implementation differs from the PermGen and this space of the heap is now automatically resized limiting the problems of going into out of memory in this region of the heap. The Metaspace memory can be garbage collected and the classes that are no longer used can be cleaned when the Metaspace reaches its maximum size.&lt;/p&gt;

&lt;p&gt;There are a few flags that can be used to control the size and the behavior of the Metaspace memory space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-XX:MetaspaceSize&lt;/strong&gt; – initial size of the Metaspace memory region,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:MaxMetaspaceSize&lt;/strong&gt; – maximum size of the Metaspace memory &amp;amp; region,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:MinMetaspaceFreeRatio&lt;/strong&gt; – minimum percentage of class metadata capacity that should be free after garbage collection,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:MaxMetaspaceFreeRatio&lt;/strong&gt; – maximum percentage of class metadata capacity that should be free after garbage collection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now imagine why some garbage collectors may need a considerable amount of time to clear the old generation space. It’s done in a single step. The tenured generation is one big space of heap and to clear it the application threads have to be stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Heap Structure of G1 Garbage Collector
&lt;/h2&gt;

&lt;p&gt;What we wrote above is true for all garbage collectors including serial, parallel and Concurrent Mark Sweep. We will discuss them a bit later. However, the G1 garbage collector goes a step further and divides the heap into something called &lt;strong&gt;regions&lt;/strong&gt;. A &lt;strong&gt;region&lt;/strong&gt; is a small, independent heap that can be dynamically set to be of Eden, Survivor or Tenured type:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F15vbwyqcj9rselwvis6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F15vbwyqcj9rselwvis6b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to the three mentioned types, we also have free memory, the white cells on the image.&lt;/p&gt;

&lt;p&gt;Such architecture allows for different operations. First of all, because the tenured generation is divided it can be collected in portions that affect latency, making the garbage collector faster for old generation space. Such heaps can be easily defragmented and dynamically resized. No cons, right? Well, that’s actually not true. The cost of maintaining such heap architecture is higher compared to the traditional heap architecture. It requires more CPU and memory.&lt;/p&gt;

&lt;p&gt;The region size when using the G1GC can be controlled. When the heap size is set to be lower than 4GB the region size will be automatically set to 1MB. For heaps between 4 and 8GB, the region size will be set to 2MB and so on, up to 32MB region size for heaps 64GB in size or larger. In general, the region size must be a power of two and be between 1 and 32MB. By default, the JVM will try to set up an optimal number of two thousand regions or more during the application start. We can control that by using the -XX:G1HeapRegionSize=N JVM parameter.&lt;/p&gt;

&lt;p&gt;The clearing of the heap in the case of G1GC is done by copying live data out of an existing region into an empty region and discarding the old region altogether. After that, the old region is considered free and objects can be allocated to it. Freeing multiple regions at the same time allows for defragmentation and assignment of &lt;strong&gt;humongous&lt;/strong&gt; objects – ones that are larger than 50% of a heap region.&lt;/p&gt;

&lt;p&gt;You may now wonder what triggers garbage collection and that would be a great question. Common triggers for garbage collection are Eden space being full, not enough free space to allocate an object, external resources like &lt;em&gt;System.gc()&lt;/em&gt;, tools like jmap or not enough free space to create an object.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Triggers Java Garbage Collection
&lt;/h1&gt;

&lt;p&gt;To keep things even more complicated there are several types of garbage collection events. You can divide them in a very simplified way, as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minor&lt;/strong&gt; event – happen when the Eden space is full and moved data to Survivor space. So a Minor event happens within the young generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mixed&lt;/strong&gt; event – a Minor event plus reclaim of the Tenured generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full GC&lt;/strong&gt; event – a young and old generation space clearing together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even by looking at the names of the events you can see that the key in most cases will be lowering the pause times of the Mixed and Full GC events. Let’s stop discussing the garbage collection events for now. There is more to it and we could get deeper and deeper. But for now, we should be good.&lt;/p&gt;

&lt;p&gt;The next thing that I would like to mention is the &lt;strong&gt;humongous&lt;/strong&gt; object. Remember? Those are the ones that are larger than a single region in our heap when dealing with the G1 garbage collector (G1GC). Actually, any object larger than 50% of the region size is considered humongous. Those objects are not allocated in the young generation space, but instead, they are put directly in the Tenured generation. Such objects can increase the pause time of the garbage collector and can increase the risk of triggering the Full GC because of running out of continued free space.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java Garbage Collectors Types
&lt;/h1&gt;

&lt;p&gt;We now understand the basics and it’s time to understand what kind of garbage collectors we have available and how each of them works in our application. Keep in mind that different Java versions will have different garbage collectors available. For example, Java 9 will have both Concurrent Mark Sweep and G1 garbage collectors, while the older updates of Java 7 will not have the G1 garbage collector available.&lt;/p&gt;

&lt;p&gt;That said, there are five types of garbage collectors in Java:&lt;/p&gt;

&lt;h2&gt;
  
  
  Serial Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Serial garbage collector&lt;/strong&gt; is &lt;strong&gt;designed&lt;/strong&gt; to be used for &lt;strong&gt;single-threaded environments&lt;/strong&gt;. Before doing garbage collection this garbage collector &lt;strong&gt;freezes&lt;/strong&gt; all the &lt;strong&gt;application threads&lt;/strong&gt;. Because of that, it is not suited for multi-threaded environments, like server-side applications. However, it is perfectly suited for single-threaded applications that don’t require low pause time. For example batch jobs.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.oracle.com/en/java/javase/13/gctuning/available-collectors.html#GUID-45794DA6-AB96-4856-A96D-FDE5F7DEE498" rel="noopener noreferrer"&gt;documentation on Java garbage collectors&lt;/a&gt; also mentions that this garbage collector may be useful on multiprocessor machines for applications with a data set up to approximately 100MB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Parallel garbage collector&lt;/strong&gt;, also known as &lt;strong&gt;throughput collector&lt;/strong&gt; is very similar to the Serial garbage collector. It also needs to freeze the application threads when doing garbage collection. But, it was designed to work on &lt;strong&gt;multiprocessor environments&lt;/strong&gt; and in multi-threaded applications with medium and large-sized data. The idea is that using &lt;strong&gt;multiple threads&lt;/strong&gt; will &lt;strong&gt;speed up garbage collection&lt;/strong&gt; making it faster for such use cases.&lt;/p&gt;

&lt;p&gt;If your application’s priority is peak performance and the thread pause time of one second or even longer is not a problem for it then the Parallel garbage collector may be a good idea. It will run from time to time freezing application threads and performing GC using multiple threads speeding it up compared to the Serial garbage collector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrent Mark Sweep Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Concurrent Mark Sweep (CMS) garbage collector&lt;/strong&gt; is one of the implementations that are called &lt;strong&gt;mostly concurrent&lt;/strong&gt;. They perform &lt;strong&gt;expensive operations&lt;/strong&gt; using &lt;strong&gt;multiple threads&lt;/strong&gt;. They also &lt;strong&gt;share&lt;/strong&gt; the &lt;strong&gt;threads&lt;/strong&gt; used for &lt;strong&gt;garbage collection&lt;/strong&gt; with the &lt;strong&gt;application&lt;/strong&gt;. The overhead for this type of garbage collection comes not only from the fact that they do the collection concurrently, but also that the concurrent collection must be enabled.&lt;/p&gt;

&lt;p&gt;The CMS GC is designed for applications that prefer short pauses. Basically, it performs slower compared to Parallel or Serial garbage collector but doesn’t have to stop the application threads to perform garbage collection.&lt;/p&gt;

&lt;p&gt;This garbage collector should be chosen if your application prefers short pauses and can afford to share the application threads with the garbage collector. Keep in mind though that the Concurrent Mark Sweep garbage collector is doing to be removed in Java 14 and you should look at the G1 garbage collector if you are not using it yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  G1 Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;G1 garbage collector&lt;/strong&gt; is the garbage collection algorithm that was introduced with the 4th update of the 7th version of Java and improved since. G1GC was designed to be low latency, but that comes at a price – more frequent work which means more CPU cycles spent in garbage collection. It partitions the heap into smaller regions allowing for easier garbage collection and &lt;strong&gt;evacuation style memory clearing&lt;/strong&gt;. It means that the objects are moved out of the cleared region and copied to another region. Most of the garbage collection is done in the young generation where it’s most efficient to do so.&lt;/p&gt;

&lt;p&gt;As the &lt;a href="https://docs.oracle.com/en/java/javase/13/gctuning/available-collectors.html#GUID-13943556-F521-4287-AAAA-AE5DE68777CD" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; states, the G1GC was designed for server-style applications running in a multiprocessor environment with a large amount of memory available. It tries to meet garbage collector pause goals with high probability. While doing that it also tries to achieve high throughput. All of that without the needs of complicated configuration, at least in theory.&lt;/p&gt;

&lt;p&gt;Think about it this way – if you have services that are &lt;strong&gt;latency-sensitive G1&lt;/strong&gt; garbage collector may be a &lt;strong&gt;very good choice&lt;/strong&gt;. Having low latencies means that those services will not suffer from long stop-the-world events. Of course at the &lt;strong&gt;cost of higher CPU usage&lt;/strong&gt;. Also, the G1 garbage collector was designed to work with larger heap sizes – if you have heap larger than 32GB G1 is usually a good choice. The G1 garbage collector is a replacement for the CMS garbage collector and it’s also the default garbage collector in the most recent Java versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Z Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Z garbage collector&lt;/strong&gt; is an experimental garbage collection implementation still not available on all platforms, like Windows and macOS. It is designed to be a very scalable low latency implementation. It performs expensive garbage collection work concurrently without the need for stopping the application threads.&lt;/p&gt;

&lt;p&gt;The ZGC is expected to work well with applications requiring pauses of 10ms or less and ones that use very large heaps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java Garbage Collection Benefits
&lt;/h1&gt;

&lt;p&gt;There are &lt;strong&gt;multiple benefits&lt;/strong&gt; of garbage collection in Java. However, the major one, that you may not think about in the first place is the &lt;strong&gt;simplified code&lt;/strong&gt;. We don’t have to worry about proper memory assignment and release cycles. In our code, we just stop using an object and the memory it is using will be &lt;strong&gt;automatically reclaimed&lt;/strong&gt; at some point. This is yet another added value from a simplicity point of view. The memory reclaim process is automatic and is the job of the internal algorithm inside the JVM. We just control what kind of algorithm we want to use – if we want to control it. Of course, we can still hit memory leaks if we keep the references to the objects forever, but this is a different pair of shoes.&lt;/p&gt;

&lt;p&gt;We have to remember though that those benefits come at a price – &lt;strong&gt;performance&lt;/strong&gt;. Depending on the situation and the garbage collection algorithm, we can pay for the ease and automation of the memory management in the CPU cycles spent on the garbage collection. In extreme cases, when we have issues with memory or garbage collection, we can even experience stop of the whole application until the space reclamation process ends.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java Garbage Collection Best Practices
&lt;/h1&gt;

&lt;p&gt;We will cover the process of tuning garbage collection in the next post in the series, but before that, we wanted to share some good and bad practices around garbage collection. First of all – you should avoid calling the System.gc() method to ask for explicit garbage collection. As we’ve mentioned it is considered a bad practice and should be avoided.&lt;/p&gt;

&lt;p&gt;The second thing I wanted to mention is the right amount of heap memory. If you don’t have enough memory for your application to work you will experience slowdowns, long garbage collection, stop the world events and eventually out of memory errors. All of that can indicate that your heap is too small, but can also mean that you have a memory leak in your application. Look at the &lt;a href="https://sematext.com/spm/" rel="noopener noreferrer"&gt;JVM monitoring&lt;/a&gt; of your choice to see if the heap usage grows indefinitely – if it is, it may mean you have a bug in your application code. We will talk more about the heap size in the next post in the series.&lt;/p&gt;

&lt;p&gt;Finally, if you are running a small, standalone application, you will probably not need any kind of garbage collection tuning. Just go with the defaults and you should be more than fine.&lt;/p&gt;

&lt;p&gt;The next step after that would be to choose the right garbage collector implementation. The one that matches the needs and requirements of our business. How to do that and what are the options to tune different garbage collection algorithms – this is something that we will cover in the next blog post – the one called A Step-by-Step Guide to Java Garbage Collection Tuning.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;At this point, we know how the Java garbage collection process looks like, how each garbage collector works and what behavior we can expect from each of them. In addition to that, in the &lt;a href="https://sematext.com/blog/java-garbage-collection-logs/" rel="noopener noreferrer"&gt;previous blog post&lt;/a&gt;, we also discussed how to turn on and understand the logs produced by each garbage collector. This means that we are ready for the final part of the series – tuning our garbage collector.&lt;/p&gt;

</description>
      <category>java</category>
      <category>gc</category>
      <category>observability</category>
      <category>performance</category>
    </item>
    <item>
      <title>Java Garbage Collection Logs &amp; How to Analyze Them</title>
      <dc:creator>Rafał Kuć</dc:creator>
      <pubDate>Thu, 19 Dec 2019 14:47:25 +0000</pubDate>
      <link>https://dev.to/sematext/java-garbage-collection-logs-how-to-analyze-them-4hgb</link>
      <guid>https://dev.to/sematext/java-garbage-collection-logs-how-to-analyze-them-4hgb</guid>
      <description>&lt;p&gt;When working with Java or any other JVM-based programming language we get certain functionalities for free. One of those functionalities is clearing the memory. If you’ve ever used languages like C/C++ you probably remember functions like &lt;em&gt;malloc&lt;/em&gt;, &lt;em&gt;calloc&lt;/em&gt;, &lt;em&gt;realloc&lt;/em&gt; and &lt;em&gt;free&lt;/em&gt;. We needed to take care of the assignment of each byte in memory and take care of releasing the assigned memory when it was no longer needed. Without that, we were soon running into a shortage of memory leading to instability and crashes.&lt;/p&gt;

&lt;p&gt;With Java, we don’t have to worry about releasing the memory that was assigned to an object. We only need to stop using the object. It’s as simple as that. Once the object is no longer referenced from inside our code the memory can be released and re-used again.&lt;/p&gt;

&lt;p&gt;Freeing memory is done by a specialized part of the JVM called Garbage Collector.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Does the Java Garbage Collector Work
&lt;/h1&gt;

&lt;p&gt;The Java Virtual Machine runs the Garbage Collector in the background to find references that are not used. Memory used by such references can be freed and re-used. You can already see the difference compared to languages like C/C++. You don’t have to mark the object for deletion, it is enough to stop using it.&lt;/p&gt;

&lt;p&gt;The heap memory is also divided into different regions and each has its own garbage collector type. There are a few implementations of the garbage collector — and each JVM can have its own implementation as long as it meets the specification. In theory and practice, each JVM vendor can provide its own garbage collector implementation providing different performance.&lt;/p&gt;

&lt;p&gt;The simplified view over the three main regions of the JVM Heap can be visualized as follows:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjnyrt3tcopye1wj8snxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjnyrt3tcopye1wj8snxe.png" alt="JVM Heap Space"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having a healthy garbage collection process is crucial to achieving optimal performance of your JVM based applications. Because of that, we need to ensure that we &lt;a href="https://sematext.com/guides/java-monitoring/" rel="noopener noreferrer"&gt;monitor JVM and its Garbage Collector&lt;/a&gt;. By using logs we can understand what the JVM tells us about the garbage collectors’ work.&lt;/p&gt;
&lt;h1&gt;
  
  
  What Are Garbage Collection (GC) Logs
&lt;/h1&gt;

&lt;p&gt;The &lt;strong&gt;garbage collector log&lt;/strong&gt; is a text file produced by the Java Virtual Machine that describes the work of the garbage collector. It contains all the information you could need to see how the memory cleaning process works. It also shows how the garbage collector behaves and how much resources it uses. Though we can monitor our application using an APM provider or in-house built monitoring tool, the garbage collector log will be invaluable to quickly identify any potential issues and bottlenecks when it comes to heap memory utilization.&lt;/p&gt;

&lt;p&gt;An example of what you can expect to find in the garbage collection log look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-10-29T10:00:28.693-0100: 0.302: [GC (Allocation Failure) 2019-10-29T10:00:28.693-0100: 0.302: [ParNew
Desired survivor size 1114112 bytes, new threshold 1 (max 6)
- age   1:    2184256 bytes,    2184256 total
: 17472K-&amp;gt;2175K(19648K), 0.0011358 secs] 17472K-&amp;gt;2382K(63360K), 0.0012071 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2019-10-29T10:00:28.694-0100: 0.303: Total time for which application threads were stopped: 0.0012996 seconds, Stopping threads took: 0.0000088 seconds
2019-10-29T10:00:28.879-0100: 0.488: Total time for which application threads were stopped: 0.0001006 seconds, Stopping threads took: 0.0000065 seconds
2019-10-29T10:00:28.897-0100: 0.506: Total time for which application threads were stopped: 0.0000981 seconds, Stopping threads took: 0.0000076 seconds
2019-10-29T10:00:28.910-0100: 0.519: Total time for which application threads were stopped: 0.0000896 seconds, Stopping threads took: 0.0000062 seconds
2019-10-29T10:00:28.923-0100: 0.531: Total time for which application threads were stopped: 0.0000975 seconds, Stopping threads took: 0.0000069 seconds
2019-10-29T10:00:28.976-0100: 0.585: Total time for which application threads were stopped: 0.0001414 seconds, Stopping threads took: 0.0000091 seconds
2019-10-29T10:00:28.982-0100: 0.590: [GC (Allocation Failure) 2019-10-29T10:00:28.982-0100: 0.590: [ParNew
Desired survivor size 1114112 bytes, new threshold 1 (max 6)
- age   1:    1669448 bytes,    1669448 total
: 19647K-&amp;gt;2176K(19648K), 0.0032520 secs] 19854K-&amp;gt;5036K(63360K), 0.0033060 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even a very small period of time can provide a lot of information. You see allocation failures, young garbage collection, threads being stopped, memory before and after garbage collection, each event leading to the promotion of the objects inside the heap memory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl4uga6ervru4gr95shmn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl4uga6ervru4gr95shmn.png" alt="Promotion of object on the JVM Heap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Are Garbage Collection Logs Important
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqas26ub9gupdeikwhnrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqas26ub9gupdeikwhnrz.png" alt="Garbage Collector Metrics Visualized"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dealing with application performance tuning can be a long and unpleasant experience. We need to properly prepare the environment and observe the application. Check this out to learn more about &lt;a href="https://sematext.com/blog/jvm-performance-tuning/" rel="noopener noreferrer"&gt;JVM performance tuning&lt;/a&gt;. With the right observability tool, like our &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;, you get insights into crucial &lt;a href="https://sematext.com/docs/integration/jvm/" rel="noopener noreferrer"&gt;metrics&lt;/a&gt; related to the application, the JVM and the operating system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sematext.com/docs/integration/jvm/" rel="noopener noreferrer"&gt;Metrics&lt;/a&gt; are not everything though. Even the best APM tools will not give you everything. &lt;a href="https://sematext.com/docs/integration/jvm/" rel="noopener noreferrer"&gt;Metrics&lt;/a&gt; can show you patterns and historical data that will help you identify potential issues, but to be able to see everything you will need to dig deeper. That deeper level in terms of a Java-based application is the garbage collection log. Even though GC logs are very verbose, they provide information that’s not available in other sources, like stop the world events and how long they took, how long the application threads were stopped, memory pool utilization and many, many more.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Enable GC Logging
&lt;/h1&gt;

&lt;p&gt;Before talking about how to enable garbage collector logging we should ask ourselves one thing. &lt;strong&gt;Should I turn on the logs by default or I should only turn them on when issues start appearing?&lt;/strong&gt; On modern devices, you shouldn’t worry about performance when enabling the garbage collector logs. Of course, you will experience a bit more writing to your persistent storage just because the logs have to be written somewhere. Apart from that, the logs shouldn’t produce any additional load on the system.&lt;/p&gt;

&lt;p&gt;You should always have the Java garbage collection logs turned on. In fact, a lot of open-source systems are already following that practice. For example, search systems like &lt;a href="https://sematext.com/resources/solr-monitoring-ebook/" rel="noopener noreferrer"&gt;Apache Solr&lt;/a&gt; or &lt;a href="https://sematext.com/resources/elasticsearch-monitoring-ebook/" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; are already including JVM flags that turn on the logs. We already know that those files include crucial information about the Java Virtual Machine operations so we know why we should have it turned on.&lt;/p&gt;

&lt;p&gt;There is a difference in terms of how you activate garbage collection logging for Java 8 and earlier and for the newer Java versions.&lt;/p&gt;

&lt;p&gt;For Java 8 and earlier you should add the following flags to your JVM based application startup parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-XX&lt;/span&gt;:+PrintGCDetails &lt;span class="nt"&gt;-Xloggc&lt;/span&gt;:&amp;lt;PATH_TO_GC_LOG_FILE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where the &lt;strong&gt;PATH_TO_GC_LOG_FILE&lt;/strong&gt; is the location of the garbage collector log file. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-XX&lt;/span&gt;:+PrintGCDetails &lt;span class="nt"&gt;-Xloggc&lt;/span&gt;:/var/log/myapp/gc.log &lt;span class="nt"&gt;-jar&lt;/span&gt; my_awesome_app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In some cases, you can also see that the &lt;strong&gt;-XX:+PrintGCTimeStamps&lt;/strong&gt; is included. However, it is redundant here and not needed.&lt;/p&gt;

&lt;p&gt;For Java 9 and newer you can simplify the command above and add the following flag to the application startup parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-Xlog&lt;/span&gt;:gc&lt;span class="k"&gt;*&lt;/span&gt;:file&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;PATH_TO_GC_LOG_FILE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-Xlog&lt;/span&gt;:gc&lt;span class="k"&gt;*&lt;/span&gt;:file&lt;span class="o"&gt;=&lt;/span&gt;/var/log/myapp/gc.log &lt;span class="nt"&gt;-jar&lt;/span&gt; my_awesome_app.jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you enable the logs it’s important to remember the GC logs rotation. When using an older JVM version, like JDK 8 you may want to rotate your GC logs. To do that we have three flags that we can add to our JVM application startup parameters. The first one is the flag that enables GC logs rotation: &lt;strong&gt;-XX:+UseGCLogFileRotation&lt;/strong&gt;. The second property &lt;strong&gt;-XX:NumberOfGCLogFiles&lt;/strong&gt; tells the JVM how many GC log files should be kept. For example including &lt;strong&gt;-XX:NumberOfGCLogFiles=10&lt;/strong&gt; will enable up to 10 GC log files. Finally the &lt;strong&gt;-XX:GCLogFileSize&lt;/strong&gt; tells how large a single GC log file can be. For example &lt;strong&gt;-XX:GCLogFileSize=10m&lt;/strong&gt; will rotate the GC log file when it reaches 10 megabytes.&lt;/p&gt;

&lt;p&gt;When using JDK 11 and the G1GC garbage collector to control your GC logs you will want to include property like this: &lt;strong&gt;java -Xlog:gc*:file=gc.log,filecount=10,filesize=10m&lt;/strong&gt;. This will result in exactly the same behavior. we will have up to 10 GC log files with up to 10 megabytes in size.&lt;/p&gt;

&lt;p&gt;Now that we know how important the JVM garbage collector logs are, and we’ve turned then on by default, we can start analyzing them.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Analyze GC Logs
&lt;/h1&gt;

&lt;p&gt;Understanding garbage collection logs is not easy. It requires an understanding of how the Java virtual machine works and the understanding of memory usage of the application. In this blog post, we will skip the analysis of the application as it differs from application to application and requires knowledge of the code. What we will discuss though is how to read and analyze the garbage collection logs that we can get out of the JVM.&lt;/p&gt;

&lt;p&gt;What is also very important is that there are various JVM versions and multiple garbage collector implementations. You can still encounter Java 7, 8, 9 and so on. Some companies still use Java 6 because of various reasons. Each version may be running different garbage collectors — Serial, Parallel, Concurrent Mark Sweep, G1 or even Shenandoah or Z. You can expect different Java versions and different garbage collector implementations to output a slightly different log format and of course we will not be discussing all of them. In fact, we will show you only a small portion of the logs, but such that should help you in understanding all other garbage collector logs as well.&lt;/p&gt;

&lt;p&gt;The garbage collection logs will be able to answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When was the young generation garbage collector used?&lt;/li&gt;
&lt;li&gt;When was the old generation garbage collector used?&lt;/li&gt;
&lt;li&gt;How many garbage collections were run?&lt;/li&gt;
&lt;li&gt;For how long were the garbage collectors running?&lt;/li&gt;
&lt;li&gt;What was the memory utilization before and after garbage collection?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s now look at an example taken out of a JVM garbage collector log and analyze each fragment highlighting the crucial parts behind it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Parallel and Concurrent Mark Sweep Garbage Collectors
&lt;/h1&gt;

&lt;p&gt;Let’s start by looking at Java 8 and the Parallel collector for the young generation space and the Concurrent Mark Sweep garbage collector for the old generation. A single line coming from our JVM garbage collector can look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-10-30T11:13:00.920-0100: 6.399: [Full GC (Allocation Failure) 2019-10-30T11:13:00.920-0100: 6.399: [CMS: 43711K-&amp;gt;43711K(43712K), 0.1417937 secs] 63359K-&amp;gt;48737K(63360K), [Metaspace: 47130K-&amp;gt;47130K(1093632K)], 0.1418689 secs] [Times: user=0.14 sys=0.00, real=0.14 secs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First of all, you can see the date and time of the event which in our case is &lt;strong&gt;2019–10–30T11:13:00.920–0100&lt;/strong&gt;. This is the time when the event happened so that you can see what happened and when it happened.&lt;/p&gt;

&lt;p&gt;The next thing we can see in the logline above is the type of garbage collection. In our case, it is Full GC and you can also expect GC as a value here. There are three types of garbage collector events that can happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minor garbage collection&lt;/li&gt;
&lt;li&gt;Major garbage collection&lt;/li&gt;
&lt;li&gt;Full garbage collection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Minor garbage collection&lt;/strong&gt; means that the &lt;strong&gt;young generation&lt;/strong&gt; space clearing event was performed by the JVM. The minor garbage collector will always be triggered when there is not enough memory to allocate a new object on the heap, i.e. when the Eden generation is full or is getting close to being full. If your application creates new objects very often you can expect the minor garbage collector to run often. What you should remember is that during minor garbage collection, when cleaning the Eden and survivor spaces the data is copied entirely which means that no memory fragmentation will happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Major garbage&lt;/strong&gt; collection means that the &lt;strong&gt;tenured generation&lt;/strong&gt; clearing event was performed. The tenured generation is also widely called the old generation space. Depending on the garbage collector and its settings the tenured generation cleaning may happen less or more often. Which is better? The right answer depends on the use-case and we will not be covering that in this blog post.&lt;/p&gt;

&lt;p&gt;Java &lt;strong&gt;Full GC&lt;/strong&gt; means that the full garbage collection event happened. Meaning that &lt;strong&gt;both&lt;/strong&gt; the &lt;strong&gt;young&lt;/strong&gt; and &lt;strong&gt;old generation&lt;/strong&gt; was cleared. The garbage collector tried to clear it and the log tells us what the outcome of that procedure was. Tenured generation cleaning requires mark, sweep and compact phases to avoid high memory fragmentation. If a garbage collector wouldn’t care about memory fragmentation you could end up in a situation where you have enough memory, but it is fragmented and the object can’t be allocated. We can illustrate this situation with the following diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsyd0sgmtot178d1k1c2p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsyd0sgmtot178d1k1c2p.png" alt="Memory Fragmentation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also one part that we didn’t discuss — the Allocation Failure. The Allocation Failure part of the garbage collector logline explains why the garbage collection cycle started. It usually means that there was no space left for new object allocation in the Eden space of heap memory and the garbage collector tried to free some memory for new objects. The Allocation Failure can also be generated by the remark phase of the Concurrent Mark Sweep garbage collector.&lt;/p&gt;

&lt;p&gt;The next important thing in the logline is the information about the memory occupation before and after the garbage collection process. Let’s look into the line once again in greater detail:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fejtwtmbobukj6wg5zib3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fejtwtmbobukj6wg5zib3.png" alt="GC Log Line Analysis"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see that the line contains a lot of useful information. In addition to what we already discussed we also have information about the memory both before and after the collection. We have the time garbage collection took and CPU resources used during the garbage collection process. As you can see we have a lot of information allowing us to see how fast or slow the process is.&lt;/p&gt;

&lt;p&gt;One piece of the very important information that the JVM garbage collector gives us is the total time for which the application threads are stopped. You can expect the threads to be stopped very often, but for a very short period of time. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-10-29T10:00:28.879-0100: 0.488: Total time for which application threads were stopped: 0.0001006 seconds, Stopping threads took: 0.0000065 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that the threads were stopped for 0.0001006 seconds and the stopping of the threads took 0.0000065 seconds. This is not a long time for threads to be stopped and you will see information like this over and over again in your garbage collector logs. What should raise a red flag is a long thread stop time — also called a stop the world event that will basically stop your application. Here’s an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-11-02T17:11:54.259-0100: 7.438: Total time for which application threads were stopped: 11.2305001 seconds, Stopping threads took: 0.5230011 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the logline above, we can see that the application threads were stopped for more than 11 seconds. What does that mean? Basically, your application was not responding for more than 11 seconds. It wasn’t responding to any requests, it wasn’t processing data and the JVM was only doing garbage collection. You want to avoid situations like this at all costs. It is a sign of a big memory problem. Either your memory is too low for your application to properly do its job or you have a memory leak that fills up your heap space eventually leading to long garbage collection and finally to running out of memory. This means that your applications will not be able to create new objects and will stop working.&lt;/p&gt;

&lt;h1&gt;
  
  
  G1 Garbage Collector
&lt;/h1&gt;

&lt;p&gt;Let’s now look at what the G1 garbage collector looks like. We will disable the previously used CMS garbage collector and turn on G1GC by using the following application options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-XX:+UseG1GC&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-XX:-UseConcMarkSweepGC&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-XX:-UseCMSInitiatingOccupancyOnly&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we turn on the G1 garbage collector and remove the Concurrent Mark Sweep.&lt;/p&gt;

&lt;p&gt;A standard G1 garbage collector log entry looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-11-03T21:26:21.827-0100: 2.069: [GC pause (G1 Evacuation Pause) (young)
Desired survivor size 2097152 bytes, new threshold 15 (max 15)
- age   1:     341608 bytes,     341608 total
, 0.0021740 secs]
   [Parallel Time: 0.9 ms, GC Workers: 10]
      [GC Worker Start (ms): Min: 2069.4, Avg: 2069.5, Max: 2069.6, Diff: 0.1]
      [Ext Root Scanning (ms): Min: 0.1, Avg: 0.2, Max: 0.4, Diff: 0.3, Sum: 1.5]
      [Update RS (ms): Min: 0.1, Avg: 0.2, Max: 0.3, Diff: 0.2, Sum: 2.3]
         [Processed Buffers: Min: 1, Avg: 1.4, Max: 4, Diff: 3, Sum: 14]
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Object Copy (ms): Min: 0.2, Avg: 0.3, Max: 0.3, Diff: 0.1, Sum: 3.0]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 10]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 0.6, Avg: 0.7, Max: 0.8, Diff: 0.1, Sum: 7.0]
      [GC Worker End (ms): Min: 2070.2, Avg: 2070.2, Max: 2070.2, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.2 ms]
   [Other: 1.1 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.8 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.2 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 26.0M(26.0M)-&amp;gt;0.0B(30.0M) Survivors: 5120.0K-&amp;gt;3072.0K Heap: 51.4M(64.0M)-&amp;gt;22.6M(64.0M)]
 [Times: user=0.01 sys=0.00, real=0.01 secs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the logline above you can see that we had a young generation garbage collection event &lt;strong&gt;[GC pause (G1 Evacuation Pause) (young)&lt;/strong&gt;, which resulted in certain regions of memory being cleared: &lt;strong&gt;[Eden: 26.0M(26.0M)-&amp;gt;0.0B(30.0M) Survivors: 5120.0K-&amp;gt;3072.0K Heap: 51.4M(64.0M)-&amp;gt;22.6M(64.0M)]&lt;/strong&gt;. We also have the timing information and CPU usage &lt;strong&gt;[Times: user=0.01 sys=0.00, real=0.01 secs]&lt;/strong&gt;. The timings are exactly the same as in the previous garbage collector discussion. The user and system scope CPU usage during the garbage collection process and we have the time it took.&lt;/p&gt;

&lt;p&gt;The memory information summary is detailed and gives us an overview of what happened. We can see that the Eden space was fully cleared Eden: &lt;strong&gt;26.0M(26.0M)-&amp;gt;0.0B(30.0M)&lt;/strong&gt;. The garbage collection started when it was occupied by 26M of data. After the garbage collection, we ended with a completely empty Eden space. The total size of the Eden space at the point of garbage collection was 30MB. The garbage collection started with the survivors’ space having 5120K of memory and ended with 3072K of data in it. Finally, the whole heap started with 51.4M occupied out of the total size of 64M and ended with 22.6M of occupation.&lt;/p&gt;

&lt;p&gt;In addition to that, you also see more detailed information about the internals of the parallel garbage collector workers and the phases of their work — like the start, scanning and working.&lt;/p&gt;

&lt;p&gt;You can also see additional log entries related to G1 garbage collector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2019-11-03T21:26:23.704-0100: 2019-11-03T21:26:23.704-0100: 3.946: 3.946: [GC concurrent-root-region-scan-start]
Total time for which application threads were stopped: 0.0035771 seconds, Stopping threads took: 0.0000111 seconds
2019-11-03T21:26:23.706-0100: 3.948: [GC concurrent-root-region-scan-end, 0.0017994 secs]
2019-11-03T21:26:23.706-0100: 3.948: [GC concurrent-mark-start]
2019-11-03T21:26:23.737-0100: 3.979: [GC concurrent-mark-end, 0.0315921 secs]
2019-11-03T21:26:23.737-0100: 3.979: [GC remark 2019-11-03T21:26:23.737-0100: 3.979: [Finalize Marking, 0.0002017 secs] 2019-11-03T21:26:23.738-0100: 3.980: [GC ref-proc, 0.0004151 secs] 2019-11-03T21:26:23.738-0100: 3.980: [Unloading, 0.0025065 secs], 0.0033738 secs]
 [Times: user=0.04 sys=0.01, real=0.01 secs]
2019-11-03T21:26:23.741-0100: 3.983: Total time for which application threads were stopped: 0.0034705 seconds, Stopping threads took: 0.0000308 seconds
2019-11-03T21:26:23.741-0100: 3.983: [GC cleanup 54M-&amp;gt;54M(64M), 0.0004419 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, the above log lines are different, but the principles still stand. The log gives us information about the total time for which the application threads were stopped, the result of the cleanup done by the garbage collector and the resources used.&lt;/p&gt;

&lt;h1&gt;
  
  
  GC Logging Options in Java 9 and Newer
&lt;/h1&gt;

&lt;p&gt;We can even go deeper with garbage collection and turn on the debug level. Let’s take Java 10 as an example and let’s include the &lt;strong&gt;-Xlog:gc*,gc+phases=debug&lt;/strong&gt; to the startup parameters of the JVM. This will turn on debug level logging for the garbage collection phases for the default G1 garbage collector on Java 10. This will enable verbose GC logging giving you extensive information about garbage collector work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0.006s][info][gc,heap] Heap region size: 1M
[0.012s][info][gc     ] Using G1
[0.013s][info][gc,heap,coops] Heap address: 0x00000006c0000000, size: 4096 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.428s][info][gc,start     ] GC(0) Pause Young (G1 Evacuation Pause)
[0.428s][info][gc,task      ] GC(0) Using 2 workers of 2 for evacuation
[0.432s][info][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Prepare TLABs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Choose Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Humongous Register: 0.0ms
[0.433s][info ][gc,phases    ] GC(0)   Evacuate Collection Set: 3.8ms
[0.433s][debug][gc,phases    ] GC(0)     Ext Root Scanning (ms):   Min:  0.6, Avg:  0.7, Max:  0.8, Diff:  0.2, Sum:  1.4, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Update RS (ms):           Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Processed Buffers:        Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Scanned Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Skipped Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Scan RS (ms):             Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Scanned Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Claimed Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Skipped Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Code Root Scanning (ms):  Min:  0.0, Avg:  0.1, Max:  0.1, Diff:  0.1, Sum:  0.1, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     AOT Root Scanning (ms):   skipped
[0.433s][debug][gc,phases    ] GC(0)     Object Copy (ms):         Min:  2.8, Avg:  2.9, Max:  3.0, Diff:  0.2, Sum:  5.7, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Termination (ms):         Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Termination Attempts:     Min: 1, Avg:  1.0, Max: 1, Diff: 0, Sum: 2, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     GC Worker Other (ms):     Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     GC Worker Total (ms):     Min:  3.6, Avg:  3.6, Max:  3.7, Diff:  0.1, Sum:  7.3, Workers: 2
[0.433s][info ][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.1ms
[0.433s][debug][gc,phases    ] GC(0)     Code Roots Fixup: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Preserve CM Refs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Reference Processing: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Clear Card Table: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Reference Enqueuing: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Merge Per-Thread State: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Code Roots Purge: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Redirty Cards: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     DerivedPointerTable Update: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Free Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Humongous Reclaim: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Start New Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Resize TLABs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Expand Heap After Collection: 0.0ms
[0.433s][info ][gc,phases    ] GC(0)   Other: 0.2ms
[0.433s][info ][gc,heap      ] GC(0) Eden regions: 7-&amp;gt;0(72)
[0.433s][info ][gc,heap      ] GC(0) Survivor regions: 0-&amp;gt;1(1)
[0.433s][info ][gc,heap      ] GC(0) Old regions: 0-&amp;gt;1
[0.433s][info ][gc,heap      ] GC(0) Humongous regions: 6-&amp;gt;3
[0.433s][info ][gc,metaspace ] GC(0) Metaspace: 9281K-&amp;gt;9281K(1058816K)
[0.433s][info ][gc           ] GC(0) Pause Young (G1 Evacuation Pause) 13M-&amp;gt;4M(122M) 4.752ms
[0.433s][info ][gc,cpu       ] GC(0) User=0.00s Sys=0.01s Real=0.00s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the exact timings in the highlighter section of the logline above. They were not present in the G1 garbage collector log that we were discussing earlier. Of course, phases are not the only option that you can turn on. Those are options that became available with Java 9 and are here to correspond to the flags that were removed or deprecated. Here are some of the options available in the earlier Java Virtual Machine versions and the options that they translate to in Java 9 and newer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintHeapAtGC&lt;/strong&gt; can now be expressed as &lt;strong&gt;-Xlog:gc+heap=debug&lt;/strong&gt; option&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintParallelOldGCPhasesTimes&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+phases*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintGCApplicationConcurrentTime&lt;/strong&gt; and &lt;strong&gt;-XX:+PrintGCApplicationStoppedTime&lt;/strong&gt; can now be expressed as &lt;strong&gt;-Xlog:safepoint&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+G1PrintHeapRegions&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+region*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+SummarizeConcMark&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+marking*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+SummarizeRSetStats&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+remset*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintJNIGCStalls&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+jni*=debug&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintTaskqueue&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+task+stats*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+TraceDynamicGCThreads&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+task*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintAdaptiveSizePolicy&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+ergo*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;-XX:+PrintTenuringDistribution&lt;/strong&gt; can be expressed as &lt;strong&gt;-Xlog:gc+age*=trace&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can combine multiple options or enable all of them by adding the &lt;strong&gt;-Xlog:all=trace&lt;/strong&gt; flag to your JVM application startup parameters. But be aware that it can result in quite a lot of information in the garbage collector log files. To avoid the flood of information you can set it to debug using &lt;strong&gt;-Xlog:all=debug&lt;/strong&gt; — it will lower down the amount of information, but it will give you way more than the standard garbage collector log.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java Garbage Collection Logging: Log Analysis Tools you Need to Know About
&lt;/h1&gt;

&lt;p&gt;There are &lt;a href="https://sematext.com/blog/log-analysis/" rel="noopener noreferrer"&gt;log analysis tools&lt;/a&gt; that can help you analyze the garbage collector logs. Nothing available out of the box in the standard Java Virtual Machine distribution though.&lt;/p&gt;

&lt;h1&gt;
  
  
  APM &amp;amp; Observability Tools
&lt;/h1&gt;

&lt;p&gt;When it comes to observing the high-level overview of the performance of the Java garbage collector, you can use one of the observability tools providing Java application-level monitoring.For example, our own &lt;a href="https://sematext.com/spm/" rel="noopener noreferrer"&gt;Sematext JVM Monitoring&lt;/a&gt; provided by &lt;a href="https://sematext.com/cloud/" rel="noopener noreferrer"&gt;Sematext Cloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A tool like this should give you summary information about how the garbage collector works, the times, collection count the maximum collection time and the average collection size. In most cases, this is more than enough to spot issues with the garbage collection without the need of going deep into the logs and analyzing them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fme47hcznusa1ddp23l32.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fme47hcznusa1ddp23l32.png" alt="JVM GC Metrics Visualized"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, when troubleshooting you may need to have a more fine-grained view over what was happening inside the garbage collector in the JVM. If you don’t want to analyze the data manually there are tools that can help you.&lt;/p&gt;

&lt;h1&gt;
  
  
  GCViewer
&lt;/h1&gt;

&lt;p&gt;For example one of the tools that can help you visualize the GC logs is the &lt;a href="http://www.tagtraum.com/gcviewer.html" rel="noopener noreferrer"&gt;GCViewer&lt;/a&gt;. A tool that allows you to analyze the garbage collector logs up to Java 1.5 and its &lt;a href="https://github.com/chewiebug/GCViewer" rel="noopener noreferrer"&gt;continuation&lt;/a&gt; aiming to support newer Java versions and the G1 garbage collector.&lt;/p&gt;

&lt;p&gt;The GC Viewer aims to provide comprehensive information about memory utilization and the garbage collector process overall. It is open-sourced and completely free for personal and commercial use aiming to provide support up to and including Java 8 and with unified logging for OpenJDK 9 and 10.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc69d9kgl730auvest9cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc69d9kgl730auvest9cq.png" alt="GC Viewer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  GCEasy
&lt;/h1&gt;

&lt;p&gt;There are also tools that are proprietary and commercial. One of them is &lt;a href="https://gceasy.io/" rel="noopener noreferrer"&gt;GCEasy&lt;/a&gt;. This is an online GC log analyzer tool where you can upload the garbage collection log and get the results in the form of an easy to read log analysis report:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flbq5gb53igm1io4xo9i2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Flbq5gb53igm1io4xo9i2.png" alt="GC Easy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The report will include information like generation size and maximum size, key performance indicators like average and maximum pause time, pauses statistics, memory leak information and interactive graphs showing you each heap memory space. All of that information calculated on the basis of the log file that you provide.&lt;/p&gt;

&lt;p&gt;Even though the GCEasy has a free plan it is limited. At the time of writing a single user could upload 5 GC log files a month with up to 50mb per file. There are additional plans available if you are interested in using the tool.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;Understanding garbage collector logs is not easy. A large number of possible formats, different Java Virtual Machine versions, and different garbage collector implementations don’t make it simpler. Even though there are a lot of options you have to remember, certain parts are common. Each garbage collector will tell you the size of the heap, the before and after occupancy of the region of the heap that was cleared. Finally, you will also see the time and resources used to perform the operation. Start from that and continue the journey of understanding the JVM garbage collection process and the memory usage of your application. Happy analysis :)&lt;/p&gt;

</description>
      <category>java</category>
      <category>gc</category>
      <category>logs</category>
      <category>observability</category>
    </item>
  </channel>
</rss>
