Logging GELF Log messages to Seq in Kotlin
Published: 2021-10-25 06:40:46

Some weeks ago I did my first task in Kotlin to send log messages in Graylog format to Seq. This was a great introduction into Kotlin for me. This article shows a simple way of logging GELF messages to Seq.

The importance of logging in applications cannot be overemphasized. Logging generates a detailed set of events that occur within an application. These events include warnings, information, error, verbose and so on. They help in finding the causes of an application problem.

####What is GELF?
GELF stands for Graylog Extended Log Format. It is a structured log event format that is implemented for logging libraries in many programming languages. Every log message in GELF contains the following fields:
* host (the creator of the message)
* timestamp
* version
* long and short version of the message
* other custom fields you can freely configure on your own

###What is Seq?
Seq is a centralized log file that is built for modern structured logging with message templates. Seq makes it easy to pin point log messages and this increases the speed of identifying and diagnosing problems in complex applications and microservices. Seq accepts logs via HTTP, GELF, custom inputs, with integrations available for .NET Core, JAVA, Python, Ruby and many other technologies.

###Prerequisites
* An Integrated Development Environment
* Java Runtime Environment
* Docker

###Logging GELF to Seq
This section describes how to log GELF messages to Seq. Seq can receive GELF events via TCP and UDP. For this, we shall focus on UDP which stands for User Datagram Protocol. GELF is not enabled out-of-the-box, and must be enabled either of two ways:
* On Windows, Seq.Input.Gelf app is installed and configured
* On Docker/Linux, seq-input-gelf container is deployed alongside Seq container
We shall look at the second method here. Now let us code.

####Step 1- Creating a Kotlin Console project
First, we have to create a Kotlin project. I prefer to use IntelliJ IDEA because of its ease of use but you are welcome to use any IDE of your choice. I have named the project GELF_Logging. After creating the project, the directory should have the following structure

![Folder Structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3hjchlshysdjntko4q2l.PNG)
Our main focus will be in the Main.Kt file in the kotlin subfolder and also the build.gradle.kts file.
The Main.kt file which is the entry point of the application initially contains the following lines of code:
```kotlin
fun main(args: Array<String>) {
    println("Hello World!")

    // Try adding program arguments at Run/Debug configuration
    println("Program arguments: ${args.joinToString()}")
}
```
The build.gradle.kts file contains the following:
```kotlin
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    kotlin("jvm") version "1.5.10"
    application
}

group = "me.obinnaisiwekpeni"
version = "1.0-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnit()
}

tasks.withType<KotlinCompile>() {
    kotlinOptions.jvmTarget = "1.8"
}

application {
    mainClass.set("MainKt")
}
```
####Step 2 - Create logback.xml file
We will be using logback which is a popular logging framework in Java and SLF4J, an abstraction for various logging frameworks. We will create a logback.xml file in main/resources folder. We will put our logback config in this folder. We will keep this file empty for now.

####Step 3 - Add dependencies in build.gradle.kts file
The next thing is to add all the necessary dependencies for logging. These dependencies are SLF4J, logback and logback-gelf. Logstash-gelf can also be used in place of logback-gelf.

The dependencies in build.gradle.kts looks like this now
```kotlin
dependencies {
    testImplementation(kotlin("test"))
    implementation("org.slf4j:slf4j-api:1.7.28")
    implementation("ch.qos.logback:logback-core:1.2.3")
    implementation ("ch.qos.logback:logback-classic:1.2.3")
    implementation("de.siegmar:logback-gelf:4.0.0")
}
```
####Step 4 - Add Configuration to logback.xml file
```kotlin
<configuration>
    <appender name="gelf_seq" class="de.siegmar.logbackgelf.GelfUdpAppender">
        <graylogHost>localhost</graylogHost>
        <graylogPort>12201</graylogPort>
    </appender>
    <root level="info">
        <appender-ref ref="gelf_seq"/>
    </root>
</configuration>
```
The appender tag simply tells logback where to append the log messages to. Here we are logging to GELF with a host of localhost and port 12201 which is the default port for sending GELF messages via TCP and UDP. Also, take note of the class attribute in the appender tag. This indicates that we are using UDP. We give the appender a name gelf_seq which is used to reference our appender in the root tag.

####Step 5 - Create a docker-compose file
```docker
version: '3'
services:
    seq:
        image: datalust/seq:latest
        ports:
           - "5341:80"
        environment:
            ACCEPT_EULA: "Y"
        restart: unless-stopped
        volumes:
            - ./seq-data:/data
    seq-input-gelf:
        image: datalust/seq-input-gelf:latest
        ports:
          - "12201:12201/udp"
        environment:
          SEQ_ADDRESS: "http://seq:5341"
        restart: unless-stopped
networks:
  default:
```
The file contains the seq and seq-input-gelf services. The seq-input-gelf sends the GELF messages which it receives over UDP to the specified SEQ_ADDRESS env variable. Both services are connected using the default network.

####Step 6 - Writing our log message and starting docker container
Now it is time to test our logs. In Main.kt, write the log message you want. I have chosen to write a simple message
```kotlin
import org.slf4j.LoggerFactory

fun main(args: Array<String>) {
    val logger = LoggerFactory.getLogger("Gelf Logging")
    val message = "Welcome to Gelf Logging to Seq"
    logger.info(message)
}
```
Then we can start the docker-compose file using the command 
```docker
docker-compose up
```
If successful, you should see an information stating that Seq is listening on localhost:5341 in our case. Then run the code and the message should appear on Seq
![Seq message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjc7bxoaote4c4ejuvfa.PNG)

###Conclusion
Logging GELF to Seq is quite straightforward and Seq helps to easily visualize log messages and makes it easy for troubleshooting.

###References
* [GELF documentaton](https://www.graylog.org/features/gelf)
* [Seq documentation](https://docs.datalust.co/docs)
* [UDP](https://de.wikipedia.org/wiki/User_Datagram_Protocol)
* [Logback documentation](http://logback.qos.ch/)
* [SLF4J documentation](http://www.slf4j.org/)
* [SLF4J Maven repo](https://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.7.28) 
* [Logback Maven repo](https://mvnrepository.com/artifact/ch.qos.logback/logback-core/1.2.3) 
* [logback-gelf](https://github.com/osiegmar/logback-gelf)
* [logstash-gelf](https://github.com/mp911de/logstash-gelf)

You can find the full code on my [Github](https://github.com/obinnadtq/GELF_to_Seq)