Structured Logging — суштина, формати података и принцип рада у апликацијама

Аутор: IT Sectr Објављено: 2026-05-28 Време читања: 8 мин

Structured Logging је приступ бележењу дневника где је свака порука представљена у машински читљивом формату са паровима кључ-вредност, уместо као неструктуриран текст. За разлику од равних ниски, структурирани дневници садрже метаподатке: timestamp, ниво, модул, идентификатор захтева — и могу бити индексирани од стране аналитичких система. Према подацима O'Reilly Effective Logging, прелазак на структуриране формате смањује време проналажења инцидента са сати на минуте захваљујући могућности филтрирања по пољима. Ово је де факто стандард у савременом мобилном и серверском развоју: JSON и logfmt омогућавају обраду дневника програмима, а не очима.

Главно

  • Structured Logging — представљање дневника у формату кључ-вредност уместо равног текста, погодно за аутоматску обраду
  • JSON — најраспрострањенији формат структурираних дневника, подржан од свих савремених система за прикупљање и анализу
  • Logfmt — компактни формат од Heroku, погодан за читање од стране човека и парсирање кроз grep
  • ELK Stack — Elasticsearch, Logstash, Kibana — стандардна инфраструктура за складиштење и визуелизацију структурираних дневника
  • Контекст — идентификатор захтева, сесија корисника, верзија апликације — обавезна поља сваке структуриране поруке

Шта је Structured Logging

Structured Logging је метода бележења дневника где свака порука садржи именована поља са типизованим вредностима. Уместо ниске попут User 42 logged in from device ABC структурирани дневник изгледа као скуп поља: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.

Главна предност структурираних дневника над текстованим је могућност програмске обраде. Парсирање текстованих дневника захтева регуларне изразе и претпоставке о формату ниске. Структурирани дневници се парсирају без губитака: свако поље има познати тип и назив, што омогућава изградњу упита попут пронађи све грешке ауторизације у последњем сату за корисника 42 без додатне обраде.

Према подацима Honeycomb.io (2023), тимови који користе structured logging у продукцији откривају инциденте у просеку 4 пута брже у поређењу са тимовима који се ослањају на текстоване дневнике и grep.

Формати структурираних дневника

Structured Logging подржава неколико формата серијализације. Избор формата зависи од инфраструктуре: JSON је погодан за интеграцију са Elasticsearch и облачним системима, logfmt — за конзолни преглед кроз tail и grep, Protocol Buffers — за високоперформантне системе са ограничењима пропусног опсега.

ФорматПримерКада користити
JSON{"event":"login","user_id":42}ELK Stack, облачни сакупљачи, микросервиси
Logfmtevent=login user_id=42 duration_ms=150Конзола, tail, heroku logs
MessagePackБинарни еквивалент JSONВисокооптерећени системи, IoT

JSON — универзални формат

JSON је најраспрострањенији формат за структуриране дневнике. Подржан је нативно од свих система за прикупљање: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. JSON дневници се лако читају од стране човека и парсирају у било ком програмском језику без додатних библиотека. Главни недостатак — сувишност: сваки пар кључ-вредност захтева наводнике и двотачке, што повећава обим ускладиштених података за 30–50% у поређењу са logfmt.

Logfmt — компактни формат

Logfmt је развијен у Heroku за конзолну видљивост. Компактнији је од JSON, задржава читљивост за човека и лако се скраћује кроз cut и awk. Пример: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt не захтева екранизацију већине знакова и добро је прилагођен за stdout-логовање у контејнерима.

Зашто је Structured Logging потребан у мобилном развоју

У мобилним апликацијама Structured Logging решава три кључна задатка: проналажење узрока падова без репродукције на уређају, праћење корисничких сесија и анализу перформанси по верзијама апликације.

Текстовани дневници на мобилним уређајима су готово бескорисни — програмер не може да grep-ује дневнике на уређају корисника. Структурирани дневници се шаљу у облачне системе (Firebase, Sentry, Datadog) и тамо се индексирају. Може се направити упит: прикажи све crash-е на iOS 17.4, верзија апликације 3.2, у модулу checkouts — и добити прецизан избор за неколико секунди.

Према подацима Sentry (2024), апликације које користе structured breadcrumbs имају 60% више контекста у сваком извештају о паду у поређењу са апликацијама које логују само текст грешке. То директно утиче на брзину исправке грешке.

Алати за прикупљање и анализу

ELK Stack — Elasticsearch, Logstash, Kibana — остаје стандардна инфраструктура за рад са структурираним дневницима. Logstash прима дневнике у JSON, претвара их и шаље у Elasticsearch за индексацију, Kibana пружа визуелни интерфејс за упите и контролне табле.

За мобилне апликације популарна су облачна решења: Firebase Crashlytics са прилагођеним дневницима, Sentry са breadcrumbs, Datadog са APM праћењем. Они примају структуриране дневнике директно из мобилног SDK и не захтевају постављање сопственог позадинског система. Firebase нуди бесплатни пакет за извештаје о падовима, Sentry додаје distributed tracing, а Datadog се интегрише са APM за истовремено праћење перформанси захтева на клијенту и серверу.

Grafana Loki — алтернатива Elasticsearch, оптимизована за дневнике. Loki не индексира садржај порука подразумевано, већ користи ознаке (labels) за филтрирање. То је значајно јефтиније за складиштење и брже при упитима по фиксном скупу поља.

swift
// Structured logging кроз Swift Logger у 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

Прво правило структурираног логовања: свака порука мора да садржи идентификатор захтева или сесије. Без контекста, појединачна порука је бескорисна — немогуће је разумети на ког корисника или захтев се односи. Додајте correlation ID на почетку сесије и преносите га кроз све слојеве апликације.

Друго правило: типизација поља. Нумеричка поља (duration_ms, status_code, retry_count) треба преносити као бројеве, а не као ниске. Elasticsearch и слични системи индексирају бројеве и ниске различито: на бројеве се могу применити агрегације (просек, медијана, перцентил), на ниске — претрага пуног текста. Лажна типизација лишава могућности изградње аналитичких контролних табли.

Треће правило: избегавајте угнежђене објекте. JSON дневници са дубином угнежђења већом од 2 нивоа су тешки за филтрирање и визуелизацију. Уместо {"user": {"name": "Alice", "role": "admin"}} користите равне кључеве: user_name=Alice user_role=admin.

kotlin
// Structured logging на Android кроз 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)
    }
}

Која поља су обавезна

Минимални скуп поља за сваку структурирану поруку: timestamp у ISO 8601, level (debug/info/warn/error/fatal), logger (назив модула или класе), message (опис догађаја читљив за човека). Додатно: correlation_id, user_id (ако је познат), version (верзија апликације), platform (iOS/Android), environment (dev/staging/prod).

Без correlation_id структурирани дневници се претварају у скуп разбацаних записа које је немогуће повезати у један кориснички сценарио. Генеришите UUID при сваком покретању апликације и додајте га у све дневнике сесије. У пракси, correlation_id мора да се преноси кроз све слојеве: од UI догађаја до мрежних захтева и позадинских задатака — у супротном део дневника остаје без контекста и не учествује у аналитици. При свеобухватном праћењу, један UUID омогућава прикупљање комплетне слике корисничког пута.

Примери структурираног логовања у Swift и Kotlin

На iOS структурирано логовање се може имплементирати кроз омотач око os_log који серијализује поља у формат logfmt. На Android — кроз Timber са прилагођеним Tree који претвара поруке у JSON или logfmt пре слања на сервер.

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: поређење приступа

Избор између структурираних и текстованих дневника зависи од фазе пројекта. У раним фазама развоја, текстовани дневници су једноставнији и бржи — програмер пише поруку директно без додатних омотача. Али чим пројекат пређе границе једног тима или једног сервера, структурирани дневници постају обавезни.

КритеријумТекстовани дневнициСтруктурирани дневници
ЧитљивостВисока у конзолиСредња (захтева pretty-print)
Претрагаgrep по поднисциУпити по пољима и вредностима
АгрегацијаНије подржанаПросек, медијана, перцентили
ИнтеграцијаЗахтева парсирањеНативна у ELK/Loki/Datadog
Обим складиштењаМањи (без метаподатака)Већи (поља + вредности)

Често постављана питања

Који формат је бољи за мобилно логовање?

За слање на сервер користите JSON — нативно је подржан од Firebase Crashlytics, Sentry и Datadog. За локални преглед у Xcode или Android Studio логовима користите logfmt — компактнији је и чита се без форматирања.

Да ли треба логовати у структурираном формату на клијенту?

Да, структурирани дневници на клијенту омогућавају додавање контекста сваком извештају о паду: верзија ОС, стање мреже, последње радње корисника. Без структурираних breadcrumbs, извештај о паду садржи само стек позива без корисничког сценарија.

По чему се logfmt разликује од JSON?

Logfmt је компактнији (обим 30–50% мањи) и лакше се чита у терминалу. JSON подржава угнежђене објекте и низове, али захтева екранизацију наводника. Избор зависи од инфраструктуре: за ELK — JSON, за конзолни преглед — logfmt.

Како додати correlation ID у све дневнике?

Направите једну инстанцу UUID при покретању апликације, сачувајте је у синглтону или DI контејнеру и преносите свим логерима кроз конструктор. Алтернатива — коришћење threading-local или Continuation Local Storage у Kotlin корутинама.

Може ли се мешати структуриране и текстоване дневнике?

Може, али се не препоручује — мешање губи могућност аутоматске индексације. Ако су неки дневници текстовани, морају се парсирати регуларним изразима, што смањује перформансе и поузданост претраге. Боље је мигрирати све дневнике на структурирани формат.

Закључак

  • Structured Logging — формат дневника са паровима кључ-вредност, погодан за аутоматску индексацију и упите, за разлику од текстованих ниски
  • JSON и logfmt — главни формати: JSON универзалан за системе прикупљања, logfmt компактан за конзолни преглед и docker дневнике
  • Correlation ID — обавезно поље сваке структуриране поруке, без њега се дневници не могу повезати у корисничку сесију
  • ELK Stack и Grafana Loki — стандардна инфраструктурна решења за складиштење, индексацију и визуелизацију структурираних дневника
  • Перформансе — тимови са structured logging откривају инциденте 4 пута брже захваљујући упитима по пољима уместо grep-а по тексту
  • Типизација — бројеви се морају преносити као бројеви, а не ниске, ради могућности агрегација (просек, медијана, перцентили) у аналитичким системима

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође