Structured Logging — essence, data formats and how it works in applications

Author: IT Sectr Published: 2026-05-28 Reading time: 8 min

Structured Logging is an approach to logging where each message is represented in a machine-readable format with key-value pairs, rather than as unstructured text. Unlike flat strings, structured logs contain metadata: timestamp, level, module, request ID — and can be indexed by analysis systems. According to O'Reilly Effective Logging, switching to structured formats reduces incident search time from hours to minutes thanks to field-based filtering. This is the de facto standard in modern mobile and server development: JSON and logfmt allow logs to be processed by programs, not by eyes.

Key Takeaways

  • Structured Logging — representing logs in key-value format instead of flat text, suitable for automated processing
  • JSON — the most common structured log format, supported by all modern collection and analysis systems
  • Logfmt — a compact format from Heroku, convenient for human reading and grep parsing
  • ELK Stack — Elasticsearch, Logstash, Kibana — the standard infrastructure for storing and visualizing structured logs
  • Context — request ID, user session, app version — mandatory fields of every structured message

What is Structured Logging

Structured Logging is a method of recording logs where each message contains named fields with typed values. Instead of a string like User 42 logged in from device ABC, a structured log looks like a set of fields: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.

The main advantage of structured logs over text logs is the ability for programmatic processing. Parsing text logs requires regular expressions and assumptions about the string format. Structured logs are parsed without loss: each field has a known type and name, allowing queries like find all authentication errors in the last hour for user 42 without additional processing.

According to Honeycomb.io (2023), teams using structured logging in production detect incidents on average 4 times faster compared to teams relying on text logs and grep.

Structured Logging Formats

Structured Logging supports several serialization formats. The choice of format depends on the infrastructure: JSON is convenient for integration with Elasticsearch and cloud systems, logfmt for console viewing via tail and grep, Protocol Buffers for high-performance systems with bandwidth constraints.

FormatExampleWhen to Use
JSON{"event":"login","user_id":42}ELK Stack, cloud collectors, microservices
Logfmtevent=login user_id=42 duration_ms=150Console, tail, heroku logs
MessagePackBinary equivalent of JSONHigh-load systems, IoT

JSON — universal format

JSON is the most common format for structured logs. It is natively supported by all collection systems: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. JSON logs are easily readable by humans and parsed by any programming language without additional libraries. The main drawback is verbosity: each key-value pair requires quotes and colons, increasing stored data volume by 30–50% compared to logfmt.

Logfmt — compact format

Logfmt was developed at Heroku for console visibility. It is more compact than JSON, retains human readability, and is easily parsable with cut and awk. Example: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt does not require escaping of most characters and is well suited for stdout logging in containers.

Why Structured Logging Matters in Mobile Development

In mobile applications, Structured Logging solves three key problems: finding crash causes without reproducing on a device, tracking user sessions, and analyzing performance across app versions.

Text logs on mobile devices are almost useless — a developer cannot grep logs on a user's device. Structured logs are sent to cloud systems (Firebase, Sentry, Datadog) and indexed there. You can build a query like show all crashes on iOS 17.4, app version 3.2, in the checkouts module and get an accurate selection within seconds.

According to Sentry (2024), apps using structured breadcrumbs have 60% more context in each crash report compared to apps logging only the error text. This directly impacts bug fix speed.

Tools for Collection and Analysis

ELK Stack — Elasticsearch, Logstash, Kibana — remains the standard infrastructure for working with structured logs. Logstash receives logs in JSON, transforms and sends them to Elasticsearch for indexing, Kibana provides a visual interface for queries and dashboards.

For mobile applications, cloud solutions are popular: Firebase Crashlytics with custom logs, Sentry with breadcrumbs, Datadog with APM tracking. They accept structured logs directly from the mobile SDK and do not require deploying your own backend. Firebase provides a free package for crash reports, Sentry adds distributed tracing, and Datadog integrates with APM to track request performance on both client and server simultaneously.

Grafana Loki — an alternative to Elasticsearch optimized for logs. Loki does not index message content by default but uses labels for filtering. This is significantly cheaper to store and faster for queries on a fixed set of fields.

swift
// Structured logging via Swift Logger in JSON
struct StructuredLog {
    let event: String
    let attributes: [String: Any]
    let level: String

    func serialize() -> String {
        var base = "event=\(event) level=\(level)"
        for (key, value) in attributes {
            base += " \(key)=\(value)"
        }
        return base
    }
}

Structured Logging Best Practices

The first rule of structured logging: every message must contain a request or session identifier. Without context, an individual log is useless — it is impossible to determine which user or request it belongs to. Add a correlation ID at session start and pass it through all application layers.

The second rule: field typing. Numeric fields (duration_ms, status_code, retry_count) should be passed as numbers, not strings. Elasticsearch and similar systems index numbers and strings differently: numbers can be aggregated (average, median, percentile), strings support full-text search. Incorrect typing prevents building analytical dashboards.

The third rule: avoid nested objects. JSON logs with nesting depth beyond 2 levels are difficult to filter and visualize. Instead of {"user": {"name": "Alice", "role": "admin"}}, use flat keys: user_name=Alice user_role=admin.

kotlin
// Structured logging on Android via Timber + logfmt
class StructuredTree : Timber.Tree() {
    override fun log(priority: Int, tag: String?,
                  message: String?, t: Throwable?) {
        val level = priorityToLevel(priority)
        val logfmt = "level=$level tag=$tag message=$message"
        sendToRemote(logfmt)
    }
}

Mandatory fields

The minimum set of fields for every structured message: timestamp in ISO 8601, level (debug/info/warn/error/fatal), logger (module or class name), message (human-readable event description). Additionally: correlation_id, user_id (if known), version (app version), platform (iOS/Android), environment (dev/staging/prod).

Without correlation_id, structured logs become a collection of disjointed records that cannot be linked into a single user scenario. Generate a UUID at each app launch and add it to all session logs. In practice, correlation_id should be passed through all layers: from UI events to network requests and background tasks — otherwise some logs will remain without context and will not participate in analytics. With end-to-end tracking, a single UUID allows collecting the complete picture of the user journey.

Structured Logging Examples in Swift and Kotlin

On iOS, structured logging can be implemented via a wrapper over os_log that serializes fields into logfmt format. On Android, via Timber with a custom Tree that converts messages to JSON or logfmt before sending to the server.

swift
import OSLog

struct StructuredLogger {
    let subsystem: String
    let category: String

    func log(level: OSLogType,
              event: String,
              context: [String: Any]) {
        let oslogger = Logger(
            subsystem: subsystem,
            category: category
        )
        let fields = context.map {
            "\($0.key)=\($0.value)"
        }.joined(separator: " ")
        oslogger.log(level: level,
                     "\(event) \(fields)")
    }
}

Structured vs Unstructured: Approach Comparison

The choice between structured and text logs depends on the project stage. In early development stages, text logs are simpler and faster — the developer writes a message directly without additional wrappers. But once a project extends beyond a single team or server, structured logs become mandatory.

CriterionText LogsStructured Logs
ReadabilityHigh in consoleMedium (requires pretty-print)
Searchgrep by substringQueries by fields and values
AggregationNot supportedAverage, median, percentiles
IntegrationRequires parsingNative in ELK/Loki/Datadog
Storage volumeSmaller (no metadata)Larger (fields + values)

Frequently Asked Questions

Which format is best for mobile logging?

For server-side sending, use JSON — it is natively supported by Firebase Crashlytics, Sentry and Datadog. For local viewing in Xcode or Android Studio logs, use logfmt — it is more compact and readable without formatting.

Should I log in structured format on the client?

Yes, structured logs on the client allow adding context to each crash report: OS version, network state, recent user actions. Without structured breadcrumbs, a crash report contains only a call stack without a user scenario.

How does logfmt differ from JSON?

Logfmt is more compact (30–50% less volume) and easier to read in a terminal. JSON supports nested objects and arrays but requires quote escaping. The choice depends on infrastructure: for ELK — JSON, for console viewing — logfmt.

How to add a correlation ID to all logs?

Create a single instance of UUID at app launch, store it in a singleton or DI container, and pass it to all loggers via constructor. Alternatively, use thread-local or Continuation Local Storage in Kotlin coroutines.

Can I mix structured and text logs?

You can, but it is not recommended — mixing loses the ability for automatic indexing. If some logs are text-based, they must be parsed with regular expressions, which reduces search performance and reliability. It is better to migrate all logs to a structured format.

Summary

  • Structured Logging — a log format with key-value pairs, suitable for automatic indexing and queries, unlike text strings
  • JSON and logfmt — the main formats: JSON is universal for collection systems, logfmt is compact for console viewing and docker logs
  • Correlation ID — a mandatory field of every structured message, without it logs cannot be linked into a user session
  • ELK Stack and Grafana Loki — standard infrastructure solutions for storing, indexing and visualizing structured logs
  • Performance — teams with structured logging detect incidents 4 times faster thanks to field-based queries instead of grep by text
  • Typing — numbers should be passed as numbers, not strings, to enable aggregations (average, median, percentiles) in analytics systems

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also