facebook
Eligio Merino
Infrastructure SME with over 20 years in designing, building, securing and monitoring full-stack platforms.
Contributions by Alberto Osorio
Posted on Jun 9th 2016 As a Web App developer, a typical scenario is to implement a log framework such as log4j (Java) or log4php (PHP) into an app. But what if your boss wants to keep track of each error that several apps are throwing across different servers, all in a single log file? It would be quite a headache to do SSH into each system to run classic `tail | grep` commands per app’s log, right? It would also be a nightmare to be there 24/7 in front of several terminal windows to monitor log.error activity, right? Well, that is where Graylog comes to save the day! Follow these 10 steps to configure your Graylog Server and Web App to centralize log activity:

Configuring Your Graylog Server

  1. Log in as ‘admin’ to open your Graylog v1.3 Admin Console; typically: http://mygraylogserver:9000/ grayloglogin
  2. Create a new input (socket) where your App is going to establish connection against Graylog server. As best practice, we are choosing TCP transport for GELF (Graylog Extended Log Format, our transport serialization) since it provides nice features over UDP—such as connection based functionality and transport encryption via TLS: System>Inputs>GELF TCP>Launch New Input GraylogGelfTCP Choose a title and connection port for your new input – make sure the port is free and not being assigned to any other process in your Graylog server: grayloggelftitile Leave the rest of the values unchanged, scroll down and click Launch: GraylogGelfEnableTLS After launching your new input, it starts automatically: GraylogBackendServices
  3. Now that you have a transport and port ready to receive log messages, you need to tell Graylog where those must be centralized—a Stream suits this purpose: Streams>Create New GraylogCreateStreamButton GraylogCreatingStream After saving your new stream, it is time to edit a rule (filter) so your messages can be properly routed: graylogPHPEditRules In section 2, leave the first option on and click Add stream rule: GraylogManageStream Save the source rule as a match exactly type: GraylogStreamRule Verify your new rule appears at the bottom and click I’m done: GraylogStreamDone
  4. Start your new stream: GraylogStartStream
  5. Send a message from your application and verify that it shows up in your Graylog stream: Streams>Backend Services (PHP) GraylogPHPHistogram

Sending Messages from Your Web App

You may be wondering how to send messages from your Web App to your Graylog server. We will be using two of the most popular approaches in building platform-independent Web Apps: PHP and Java. Let’s get started:

Send Messages to Graylog from a PHP Web App

  1. The way we want to log into Graylog is to use the Graylog Extended Log Format (GELF), which can be easily integrated with PHP using the library https://github.com/bzikarsky/gelf-php by Benjamin Zikarsky. It is available on his latest version on Packagist so it can be installed with Composer on your application: composer require graylog2/gelf-php
  2. As a regular Composer application we just need to include it:
    require_once __DIR__ . '/../vendor/autoload.php';
  3. Gelf-php supports many transport libraries depending of the configuration of our Graylog installation, such as UDP, TCP, HTTP, etc. Given we’re using TCP in our installation, we use the class Gelf\Transport\TcpTransport and just set up the server and port:
    $transport = new Gelf\Transport\TcpTransport("mygraylogserver", 9000);
  4. Now, we set up our message to be logged. In this case, we take as an example a cron job that registers leads into our platform, and in case of failure we want to know the cause. Use ShortMessage to define the problem, and the FullMessage field to log the payload response we received from our request. We also have a custom field to log our request parameters, using the method setAdditional:
    $message = new Gelf\Message();
    $message->setShortMessage("Lead couldn’t be created")
        ->setLevel(\Psr\Log\LogLevel::ALERT)
        ->setFullMessage($response); //{“success”:”false”, code:”lead_duplicated”}
      ->setAdditional(‘request',$request); //{“email”:“existing_lead@mail.com”}
  5. Finally we set up the host.
      $message ->setHost("portal.backendService");
      $message->setAdditional('component',’Leads/API/create’);
Here’s the complete source code:
<?php
  require_once __DIR__ . '/../vendor/autoload.php';
$transport = new Gelf\Transport\TcpTransport("mygraylogserver", 9000);
$message = new Gelf\Message();
$message->setShortMessage("Lead couldn’t be created")
    ->setLevel(\Psr\Log\LogLevel::ALERT)
    ->setFullMessage($response) //{“success”:”false”, code:”lead_duplicated”}
  ->setAdditional('request',$request); //{“email”:“existing_lead@mail.com”}
$message ->setHost("portal.backendService");
  $message->setAdditional('component','Leads/API/create');
?>
We can also integrate Graylog with other libraries, such as log4php, with the following integration: https://github.com/d-ulyanov/log4php-graylog2 GraylogGitLog4php

Send Messages to Graylog from a Java Web App

For this example, we are going to create a JavaServer Faces (JSF) Web App in order to send a log message to our Graylog server—if you already have one with Maven support enabled, you can skip to step 3. As for our primary Java IDE, we prefer to use MyEclipse as it has the coolest features and speeds up development time. Download a free trial if you want to give it a try.
  1. Create a Web Project featuring Maven structure: Go to File>New>Project>MyEclipse>Java Enterprise Projects>Web Project and complete the wizard as shown below.
graylognewmeproject1cropNew Web Project wizard-screen 1: Enter project details as shown and click Next. graylognewmeproject2cropNew Web Project wizard-screen 2: Click Next to accept default location. graylognewmeproject3cropNew Web Project wizard-screen 3: Configure settings as shown and click Next. graylognewmeproject4cropNew Web Project wizard-screen 4: Configure Maven as shown and click Finish.
  • Add JSF to the Web Project from the MyEclipse workspace (We love that MyEclipse lets you add JSF facets directly from the context menu!!) Right-click on the graylog-test project, select MyEclipse>Project Facets>Install JavaServer Faces Facet, and then complete the wizard as shown below. graylogmeinstallfacets1cropInstall JavaServer Faces Facet wizard-screen 1: Complete as shown and click Next.graylogmeinstallfacets2cropInstall JavaServer Faces Facet wizard-screen 2: Complete as shown and click Next. graylogmeinstallfacets3cropInstall JavaServer Faces Facet wizard-screen 3: Complete as shown and click Finish.
  • Set up log4j. We are going to use Gelfj appender to tell Log4j to send messages to our Graylog server. Let’s add Maven dependencies: Right-click on the graylog-test project, select Maven>Add Dependency and complete the following steps. graylogmavendepend1Add details for Log4j libraries as shown and click OK.  Right-click on the graylog-test project and select Maven>Add Dependency to add the Gelfj libraries: graylogmavendepend2Add details for Gelfj libraries as shown and click OK.Right-click on graylog-test>WebRoot>WEB-INF and select New>File. grayloglog4jpropertiesType the file name as shown and click Finish. Now let’s do some cool stuff! Let’s send messages to our Graylog server and our Java application without implementing customized Graylog classes. Ready? Enter the following configuration in our new log4j.properties file so we can send INFO messages to Graylog and DEBUG messages to the Web App’s log file:
    # Turn off stdout 
    log4j.rootLogger=OFF
    
    # Graylog appender (Graylog server = monitor)
    log4j.graylog=INFO, graylog
    log4j.appender.graylog=org.graylog2.log.GelfAppender
    log4j.appender.graylog.graylogHost=tcp:monitor
    log4j.appender.graylog.graylogPort=12203
    log4j.appender.graylog.originHost=BackendService
    log4j.appender.graylog.layout=org.apache.log4j.PatternLayout
    log4j.appender.graylog.facility=gelf-java-appender
    log4j.appender.graylog.additionalFields={'environment': 'DEV', 'application': 'JavaApp'}
    log4j.appender.graylog.extractStacktrace=true
    log4j.appender.graylog.addExtendedInformation=true
    
    # Application appender (log file)
    log4j.appLogger=DEBUG, appLogger
    log4j.appender.appLogger=org.apache.log4j.RollingFileAppender
    log4j.appender.appLogger.MaxFileSize=15MB
    log4j.appender.appLogger.MaxBackupIndex=20
    log4j.appender.appLogger.File=${catalina.base}/logs/graylog-test.log
    log4j.appender.appLogger.layout=org.apache.log4j.PatternLayout
    log4j.appender.appLogger.layout.ConversionPattern=%d %5p [%t] (%C:%L) - %m%n
    
    log4j.category.graylogLogger=INFO, graylog
    log4j.additivity.graylog=false
    
    log4j.category.webAppLogger=DEBUG, appLogger
    log4j.additivity.appLogger=false
    Now, let’s initialize out Log4j Engine with this class:
    package com.myeclipse.graylog;
    
    import javax.servlet.http.HttpServlet;
    import org.apache.log4j.PropertyConfigurator;
    
    public class Log4jInit extends HttpServlet {
    	// Make sure to generate an unique UID
    private static final long serialVersionUID = 2351548619095521786L;
    
    	public void init() {
    		String prefix = getServletContext().getRealPath("/");
    		String file = getInitParameter("logFile");
    		if (file != null) {
    			PropertyConfigurator.configure(prefix + file);
    		}
    	}
    }
    Finally, let’s make Log4j load at Web App startup by updating our graylog-test/WebRoot/WEB-INF/web.xml file:
      <servlet>
        <servlet-name>LoggerServlet</servlet-name>
        <servlet-class>com.myeclipse.graylog.Log4jInit</servlet-class>
        <init-param>
            <param-name>logFile</param-name>
            <param-value>/WEB-INF/log4j.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
    
  • Create a JSF page to send a log message to Graylog:

    Managed Bean

    package com.myeclipse.graylog;
    
    import java.io.Serializable;
    
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.ViewScoped;
    
    import org.apache.log4j.Logger;
    
    @ManagedBean
    @ViewScoped
    public class Recovery implements Serializable {
    	private static final long serialVersionUID = -6989213978614032835L;
    	private static final Logger WebAppLogger = Logger.getLogger("webAppLogger");
    	private static final Logger GrayLogLogger = Logger.getLogger("graylogLogger");
    	
    	private String email;
    	
    	public Recovery() {
    		this.init();
    	}
    	
    	private void init() {
    		WebAppLogger.debug("Starting WebApp...");
    		this.email = new String();
    	}
    
    	public String passwordReset() {
    		// This message will NOT be sent to our Graylog server 
    		WebAppLogger.debug("Received UID = " + this.email);
    		
    		// This message will be sent to our Graylog server through our 
    		// defined 'graylog' appender in 'log4j.properties' file  
    		GrayLogLogger.info("A password reset has been requested by: " + this.email);
    		
    		return null;
    	}
    	
    	public String getEmail() {
    		return email;
    	}
    
    	public void setEmail(String email) {
    		this.email = email;
    	}
    }
    

    JSF Page

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml"
    	xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    	xmlns:h="http://xmlns.jcp.org/jsf/html"
    	xmlns:f="http://xmlns.jcp.org/jsf/core"
    	xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
    	xmlns:fn="http://xmlns.jcp.org/jsp/jstl/functions" lang="en">
    	<h:head>
    		<title>JSF Test Page For Graylog</title>
    		<meta name="keywords" content="graylog,log4j,gelfj"/>
    		<meta name="description" content="e-mail UID will be logged into Graylog"/>
    		<meta name="content-type" content="text/html; charset=UTF-8"/>
        </h:head>
    
    	<h:body>
    		<p>
    			<h:form id="recoveryForm">
    				<h:outputText value="Enter your e-mail address: " />
    				<h:inputText value="#{recovery.email}" size="32" />
    				<br />
    				<h:commandButton type="submit" value="Request Password" 
    action="#{recovery.passwordReset}" />
    			</h:form>
    		</p>
    	</h:body>
    </html>
    
  • Finally, let’s test our Java App by entering an e-mail address so we can locate our Web App log message in Graylog stream: http://localhost:8080/graylog/index.xhtml GraylogAppEmail Tailing our Web App’s log file to locate our DEBUG messages (graylog-test.log): graylogDebugMsgs On our Graylog Server admin console, locate our INFO messages: Streams>Backend Services GraylogJavaHistogram

Conclusion

Definitively, we found Graylog to be a great tool to concentrate messages such as infos, warnings and errors. Plus, it is absolutely free and (as you can see) quite easy to implement on PHP and Java applications. Until next time—happy logging! 🙂 “Success is not something you postpone for the future; it something you design for the present.”- Jim Rohn

Let Us Hear from You!

If you have any comments or questions, we would love to hear from you @MyEclipseIDE on twitter or via the MyEclipse forum. If you’re not already subscribing to our blogs, why not do it today?