Skip to content
/ maple Public

Type-safe, consistently named and formatted, structured logging wrapper for SLF4J that's ideally suited for your logging aggregator.

License

Notifications You must be signed in to change notification settings

Randgalt/maple

Repository files navigation

Build Status Maven Central

Maple

Type-safe, consistently named and formatted, structured logging wrapper for SLF4J that's ideally suited for your logging aggregator.

log.info(schema -> schema.id(userId).code(CODE_USER).qty(totalQty));

Quickstart

  • Define a logging schema interface
  • Wrap an SLF4J Logger
  • Begin structured logging

Define a logging schema interface

public interface Logging {
    Logging id(String id);
    Logging fullName(String name);
    Logging code(CodeType code);
    Logging qty(int qty);
    // etc
}

Wrap an SLF4J Logger

MapleLogger<Logging> logger = MapleFactory.getLogger(log, Logging.class);

Begin structured logging

logger.info(s -> s.id(userId).fullName("Some Person").code(CODE_USER).qty(totalQty));

// translated into SLF4J call:
slf4jLogger.info("id=XYZ123 full_name=\"Some Person\" code=user qty=1234");

Introduction

Per Thoughtworks we should log in a structured manner...

Per Splunk: "Use clear key-value pairs. One of the most powerful features of Splunk software is its ability to extract fields from events when you search, creating structure out of unstructured data."

Per Elasticsearch: "[Logging] works best when the logs are pre-parsed in a structured object, so you can search and aggregate on individual fields." It can already be done in Go or Python so why not Java?

If you export your logs to a centralized indexer, structuring your logging will make the indexer's job much easier and you will be able to get more and better information out of your logs. Manual structured logging is error prone and requires too much discipline. We can do better.

The Problem

Log files are not individually read by humans. They are aggregated and indexed by systems such as Elasticsearch and Splunk. Free form text messages are not very useful for these systems. Instead, best practices dictate that logging be transformed into fields/values for better indexing, querying and alerting.

Logging libraries have responded to this problem by providing APIs that make creating field/value logging easier. Much like Java's String.format() method you can put tokens in your log message to be replaced by runtime values. However, much like the difference between dynamically typed languages and strongly typed languages, token replacement is error prone, i.e.

  • It's easy to misspell field names
  • It's easy to transpose values in the replacement list
  • A field name in one part of the code might be spelled differently in another part of the code
  • It's hard to enforce required logging fields (e.g. "event-type")
  • No good way to prevent secure values such as passwords, keys, etc. from getting logged
  • Spaces, quotes, etc. need to be manually escaped

Structured Logging Library

  • Not a new logging library - merely a strongly typed wrapper for SLF4J
  • Strongly typed logging model provides consistent naming and field/value mapping
  • Automatic escaping/quoting of values
  • Very low overhead
  • Optional support for:
    • Object/model flattening
    • Required fields
    • "Do Not Log" fields
    • Testing utilities
    • Composed logging
    • Consistent snake-case naming

Documentation and Reference