Mladen

Logging Events Using Swift Cloud Logger

Mladen on November 27, 2017

About the Logger

Swift Cloud Logger is an application used for logging different events during the execution of your program. The main part of Cloud Logger is a server application built using Swift Kitura framework consisting of only one endpoint /logger which listens on a particular server port for requests that holds JSON body matching next struct:

struct LoggerData: Codable {
    let appName: String
    let logType: String
    let logTarget: String
    let sourceFile: String
    let lineNumber: Int
    let function: String
    let logText: String
}

When appropriate HTTP .post request with correct header (key: Content-Type, value: application/json), and matching fields is sent to listening application it can either output log message to console (terminal window) or save it to a file. By using Swift Logger Client library, it is easy to post matching requests to server-side logger from any Swift application, and use stored data for later examination.

Implementation

Starting Logging Server

The easiest way to deploy Swift Logger Server to either cloud server or local machine is by using Docker image mladenk/swift-logger. All you need is an installed and running Docker. If you need to setup Docker on a remote server, a short instruction can be found on this website - How to Install Docker Engine on a DigitalOcean Cloud. Before running Docker container and starting Swift Cloud Logger, create a directory where it will store log data files. From within that directory, only one command is required to pull the docker image, start the container and run logger application:

// create swift logger directory on server
$ mkdir logger
$ cd logger

// start logging service
$ docker run -itv $(pwd):/SwiftLogger/data -w /SwiftLogger  --name logger -p 8080:8080 mladenk/swift-logger /SwiftLogger/.build/debug/SwiftLogger

After the image is pulled from docker hub and the container is started, you will have to use standard docker escape sequence to exit from running container by pressing Ctrl-P followed by Ctrl-Q. Now, every request sent to your http://server_ip/logger endpoint and consisting of required parameters will be logged.

To examine a logged data file inside the Docker container, from console window outside container execute next command to use console within the container.

$ docker exec -it logger /bin/bash

Again, leaving running container without stopping it requires escape sequence Ctrl-P followed by Ctrl-Q

It is also a good practice and in most use cases a requirement to place your server application behind an NGINX reverse proxy. NGINX server block should be configured to pass all HTTP incoming traffic at a particular logging subdomain to a port 8080. We can define a CNAME record logging.our-domain.com and use NGINX to proxy requests to a port where our logging application listens.

// server block inside nginx configuration file
server {
    listen 80;
    server_name logging.our-domain.com;
    location / {
    proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass         http://our-domain.com:8080;
    }
}

Using Client Library

After downloading all dependancies, import SwiftLoggerClient library.

import SwiftLoggerClient

Before initialization, take note of the two enums used to define whether our server will output logged data to console only or both to file and console. The second enum is used to easily enable/disable logger.

//
// State enum is used to enable/disable logger output
//
public enum State {
    case enabled
    case disabled
}

//
// Target enum defines weather logger output will be directed to file
// or terminal only. *in case of file, terminal output won't be disabled
//
public enum Target {
    case file
    case terminal
}

Initialize new class instance with required application name, target enum (.file or .terminal), server name and state enum (.enabled or .disabled):

let log = Logger(applicationName: String, target: Target, onServer: String, state: State)

// example usage:

let log = Logger(applicationName: "My Application", target: .file, onServer: "logging.crafterll.io", state .enabled)

Also, a few public variables could be set to different values than defaults:

public let SWIFT_LOGGER_backEndSchema = "http"
public let SWIFT_LOGGER_backEndPort: Int16 = 80

That's all there is to setting your logger. To send a log event to server side, a method .debug, .info, .warning or .error has to be invoked with or without message: parameter.

// logging events with a message

log.debug(message: "This is a debug message.")
log.info(message: "This is an info message.")
log.warning(message: "This is a warning message.")
log.error(message: "An error has occurred.")

// logging events without message parameter

log.debug()
log.info()
log.warning()
log.error()

Example output from logger:

***** DEBUG ***** APP: My Application ***** Nov 27, 2017, 5:29:25 PM ***** SOURCE: main.swift ***** METHOD: myFunction() ***** AT LINE: 22 ***** >>> This is a debug message

To disable logger just change state in class instance declaration from .enabled to .disabled

Swift Logger Links to Repositories

Swift Logger Server code on GitHub pages.
Swift Logger Client code on GitHub pages.
Swift Logger Server complete Docker image.