Structured Logging är en metod för att logga där varje meddelande presenteras i ett maskinläsbart format med nyckel-värde-par, istället för ostrukturerad text. Till skillnad från platta strängar innehåller strukturerade loggar metadata: timestamp, nivå, modul, begäran-ID — och kan indexeras av analyssystem. Enligt uppgifter från O'Reilly Effective Logging, minskar övergången till strukturerade format tiden för att hitta en incident från timmar till minuter tack vare möjligheten att filtrera på fält. Detta är de facto-standard inom modern mobil- och serverutveckling: JSON och logfmt gör det möjligt att bearbeta loggar med program, inte med ögonen.
Huvudpunkter
Structured Logging är en metod för att logga där varje meddelande innehåller namngivna fält med typade värden. Istället för en sträng som User 42 logged in from device ABC ser en strukturerad logg ut som en uppsättning fält: user_id=42, event=login, device_id=ABC, timestamp=2026-07-04T10:30:00Z.
Den största fördelen med strukturerade loggar jämfört med textloggar är möjligheten till programmatisk bearbetning. Parsning av textloggar kräver reguljära uttryck och antaganden om strängformatet. Strukturerade loggar parsas utan förlust: varje fält har en känd typ och namn, vilket möjliggör byggandet av frågor som hitta alla auktoriseringsfel den senaste timmen för användare 42 utan ytterligare bearbetning.
Enligt uppgifter från Honeycomb.io (2023), upptäcker team som använder structured logging i produktion incidenter i genomsnitt 4 gånger snabbare jämfört med team som förlitar sig på textloggar och grep.
Structured Logging stödjer flera serialiseringsformat. Valet av format beror på infrastrukturen: JSON är bekvämt för integrering med Elasticsearch och molnsystem, logfmt — för konsolvisning via tail och grep, Protocol Buffers — för högpresterande system med bandbreddsbegränsningar.
| Format | Exempel | När att använda |
|---|---|---|
| JSON | {"event":"login","user_id":42} | ELK Stack, molninsamlare, mikrotjänster |
| Logfmt | event=login user_id=42 duration_ms=150 | Konsol, tail, heroku logs |
| MessagePack | Binär motsvarighet till JSON | Högt belastade system, IoT |
JSON är det vanligaste formatet för strukturerade loggar. Det stöds naturligt av alla insamlingssystem: Logstash, Fluentd, Amazon CloudWatch, Google Cloud Logging. JSON-loggar är lättlästa för människor och parsas av alla programmeringsspråk utan extra bibliotek. Den största nackdelen — redundans: varje nyckel-värde-par kräver citattecken och kolon, vilket ökar volymen på lagrade data med 30–50% jämfört med logfmt.
Logfmt utvecklades på Heroku för konsolsynlighet. Det är mer kompakt än JSON, behåller mänsklig läsbarhet och kan enkelt kapas med cut och awk. Exempel: ts=2026-07-04T10:30:00Z level=error module=api status=500. Logfmt kräver inte escaping av de flesta tecken och är väl lämpligt för stdout-loggning i containrar.
I mobilapplikationer löser Structured Logging tre viktiga uppgifter: att hitta orsaker till krascher utan reproduktion på enheten, att spåra användarsessioner och att analysera prestanda per applikationsversion.
Textloggar på mobila enheter är nästan oanvändbara — utvecklaren kan inte grep:a loggar på användarens enhet. Strukturerade loggar skickas till molnsystem (Firebase, Sentry, Datadog) och indexeras där. En fråga kan byggas: visa alla krascher på iOS 17.4, appversion 3.2, i modulen checkouts — och få ett exakt urval på några sekunder.
Enligt uppgifter från Sentry (2024), har applikationer som använder structured breadcrumbs 60% mer kontext i varje kraschrapport jämfört med applikationer som bara loggar feltexten. Detta påverkar direkt hastigheten för buggfixar.
ELK Stack — Elasticsearch, Logstash, Kibana — förblir standardinfrastrukturen för att arbeta med strukturerade loggar. Logstash tar emot loggar i JSON, omvandlar och skickar till Elasticsearch för indexering, Kibana tillhandahåller ett visuellt gränssnitt för frågor och instrumentpaneler.
För mobilapplikationer är molnlösningar populära: Firebase Crashlytics med anpassade loggar, Sentry med breadcrumbs, Datadog med APM-spårning. De tar emot strukturerade loggar direkt från mobil SDK och kräver inte distribution av egen backend. Firebase erbjuder ett gratis paket för kraschrapportering, Sentry lägger till distribuerad spårning och Datadog integreras med APM för samtidig prestandaövervakning av förfrågningar på klient och server.
Grafana Loki — ett alternativ till Elasticsearch, optimerat för loggar. Loki indexerar inte meddelandeinnehåll som standard, utan använder etiketter (labels) för filtrering. Detta är betydligt billigare att lagra och snabbare vid frågor på en fast uppsättning fält.
// Strukturerad loggning via Swift Logger till 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
}
}
Den första regeln för strukturerad loggning: varje meddelande måste innehålla en begäran- eller sessionsidentifierare. Utan kontext är en enskild logg oanvändbar — det är omöjligt att förstå vilken användare eller begäran den tillhör. Lägg till correlation ID i början av sessionen och överför det genom alla lager i applikationen.
Den andra regeln: typning av fält. Numeriska fält (duration_ms, status_code, retry_count) måste skickas som siffror, inte som strängar. Elasticsearch och liknande system indexerar siffror och strängar olika: på siffror kan aggregationer tillämpas (medelvärde, median, percentil), på strängar — fulltextsökning. Falsk typning omöjliggör byggandet av analytiska instrumentpaneler.
Den tredje regeln: undvik nästlade objekt. JSON-loggar med ett nästdjup på mer än 2 nivåer är svåra att filtrera och visualisera. Istället för {"user": {"name": "Alice", "role": "admin"}} använd platta nycklar: user_name=Alice user_role=admin.
// Strukturerad loggning på 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)
}
}
Minsta uppsättning fält för varje strukturerat meddelande: timestamp i ISO 8601, level (debug/info/warn/error/fatal), logger (modul- eller klassnamn), message (människoläsbar beskrivning av händelsen). Extra: correlation_id, user_id (om känd), version (appversion), platform (iOS/Android), environment (dev/staging/prod).
Utan correlation_id förvandlas strukturerade loggar till en samling spridda poster som inte kan kopplas till ett enda användarscenario. Generera ett UUID vid varje applikationsstart och lägg till det i alla sessionsloggar. I praktiken måste correlation ID överföras genom alla lager: från UI-händelser till nätverksförfrågningar och bakgrundsuppgifter — annars förblir en del av loggarna utan kontext och deltar inte i analysen. Vid end-to-end-spårning gör ett enda UUID det möjligt att samla en fullständig bild av användarvägen.
På iOS kan strukturerad loggning implementeras via ett omslag runt os_log som serialiserar fält till logfmt-format. På Android — via Timber med ett anpassat Tree som omvandlar meddelanden till JSON eller logfmt innan de skickas till servern.
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)")
}
}
Valet mellan strukturerade och textloggar beror på projektets fas. I tidiga utvecklingsfaser är textloggar enklare och snabbare — utvecklaren skriver meddelandet direkt utan extra omslag. Men när väl projektet överskrider gränserna för ett team eller en server blir strukturerade loggar obligatoriska.
| Kriterium | Textloggar | Strukturerade loggar |
|---|---|---|
| Läsbarhet | Hög i konsol | Medel (kräver pretty-print) |
| Sökning | grep på delsträng | Frågor på fält och värden |
| Aggregering | Stöds inte | Medelvärde, median, percentiler |
| Integration | Kräver parsning | Inbyggd i ELK/Loki/Datadog |
| Lagringsvolym | Mindre (utan metadata) | Större (fält + värden) |
Vanliga frågor
För att skicka till servern använd JSON — det stöds naturligt av Firebase Crashlytics, Sentry och Datadog. För lokal visning i Xcode eller Android Studio-loggar använd logfmt — det är mer kompakt och läsbart utan formatering.
Ja, strukturerade loggar på klienten gör det möjligt att lägga till kontext till varje kraschrapport: OS-version, nätverksstatus, användarens senaste åtgärder. Utan strukturerade breadcrumbs innehåller kraschrapporten bara anropsstacken utan användarscenario.
Logfmt är mer kompakt (30–50% mindre volym) och lättare att läsa i terminalen. JSON stödjer nästlade objekt och arrayer, men kräver escaping av citattecken. Valet beror på infrastrukturen: för ELK — JSON, för konsolvisning — logfmt.
Skapa en instans av UUID vid applikationsstart, spara den i en singleton eller DI-behållare och överför den till alla loggrar via konstruktorn. Alternativ — användning av threading-local eller Continuation Local Storage i Kotlin-korutiner.
Det går, men rekommenderas inte — blandning förlorar möjligheten till automatisk indexering. Om en del av loggarna är text måste de parsas med reguljära uttryck, vilket minskar prestanda och söktillförlitlighet. Bättre att migrera alla loggar till strukturerat format.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också