Centralized Logging Patterns Philipp Krenn @xeraa @xeraa

@xeraa

@xeraa

@xeraa

@xeraa

@xeraa

@xeraa

@xeraa

@xeraa

Developer @xeraa

@xeraa

@xeraa

@xeraa

@xeraa

@xeraa

Disclaimer I build highly monitored Hello World apps @xeraa

Example: Java SLF4J, Logback, MDC with logstash-logback-encoder Alternative https://github.com/vy/log4j2-logstash-layout @xeraa

And Everywhere Else .NET: NLog JavaScript: Winston Python: structlog PHP: Monolog @xeraa

Anti-Pattern: print System.out.println(“Oops”); @xeraa

Anti-Pattern: Coupling @xeraa

Parse @xeraa

@xeraa

Collect Log Lines filebeat.inputs: - type: log paths: - /mnt/logs/*.log @xeraa

Grok https://github.com/logstash-plugins/logstash-patterns-core/blob/ master/patterns/grok-patterns @xeraa

Dev Tools Grok Debugger @xeraa

[2018-09-28 10:30:38.516] ERROR net.xeraa.logging.LogMe [main] user_experience= , session=46, loop=15 Wake me up at night java.lang.RuntimeException: Bad runtime… at net.xeraa.logging.LogMe.main(LogMe.java:30) ^[%{TIMESTAMP_ISO8601:timestamp}]%{SPACE}%{LOGLEVEL:level} %{SPACE}%{USERNAME:logger}%{SPACE}[%{WORD:thread}] %{SPACE}-%{SPACE}%{GREEDYDATA:mdc}%{SPACE}-%{SPACE} %{GREEDYDATA:themessage}(?:\n+(?<stacktrace>(?:.|\r|\n)+))? @xeraa

Logstash Key Value Filter for MDC kv { source => “labels” field_split => “,” trim_key => ” ” } @xeraa

Machine Learning Data Visualizer @xeraa

Pro: No change Con: Regular expression, multiline, format changes @xeraa

Send @xeraa

@xeraa

logback.xml <appender name=”logstash” class=”net.logstash.logback.appender.LogstashAccessTcpSocketAppender”> <destination>logstash:4560</destination> <encoder class=”net.logstash.logback.encoder.LogstashEncoder”/> </appender> @xeraa

Pro: No files Con: Outages & coupling @xeraa

Structure @xeraa

@xeraa

Collect JSON filebeat.input: - type: log paths: - /mnt/logs/*.json json: message_key: message keys_under_root: true @xeraa

Stack(trace) Hash @xeraa

Pro: Right format Con: JSON serialization overhead @xeraa

Containerize @xeraa

@xeraa

Where to put Filebeat? Sidecar @xeraa

@xeraa

https://github.com/elastic/beats/tree/ master/deploy/docker @xeraa

Docker Logs filebeat.autodiscover: providers: - type: docker hints.enabled: true processors: - add_docker_metadata: ~ @xeraa

Metadata No Docker metadata with the other methods { “docker”: { “container”: { “image”: “java-logging_java_app”, “labels”: { “com”: { “docker”: { “compose”: { “container-number”: “1”, “project”: “java-logging”, “service”: “java_app”, “version”: “1.23.2”, “oneoff”: “False”, “config-hash”: “2b38df3c73c6 } } }, “app”: “fizzbuzz” }, “id”: “9d6d5a7640a457a1e08c422cb0a08 “name”: “java_app” } } 1a68a37443c2006f3f3e4fc16c3c 2a1d7793f2a38841e274b607” f96ff3631fb5356f749b2ac7d8f3719687f” , } @xeraa

Missing the Last Line Waiting for the newline @xeraa

Hints labels: - “app=fizzbuzz” - “co.elastic.logs/multiline.pattern=^\[” - “co.elastic.logs/multiline.negate=true” - “co.elastic.logs/multiline.match=after” @xeraa

Registry File filebeat.registry_file: /usr/share/filebeat/data/registry @xeraa

Ingest Pipeline output.elasticsearch: hosts: [“http://elasticsearch:9200”] index: “docker” pipelines: - pipeline: “parse_java” when.contains: docker.container.name: “java_app” @xeraa

Ingest Pipeline { “description” : “Parse Java log lines”, “processors”: [ { “grok”: { “field”: “message”, “patterns”: [ “^\[%{TIMESTAMP_ISO8601:timestamp}\]%{SPACE}%{LOGLEVEL:log.level} %{SPACE}%{USERNAME:log.package}%{SPACE}\[%{WORD:log.method}\]%{SPACE}%{SPACE}%{GREEDYDATA:labels}%{SPACE}-%{SPACE}%{GREEDYDATA:message_rest} (?:\n+(?<stacktrace>(?:.|\r|\n)+))?” ], “ignore_failure”: true } } ] } Note: \, message vs message_rest, @timestamp vs timestamp, ignore_failure @xeraa

ASCII Art . .-__ ''-._ _.- .. ”-._ .-.-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) |`-._`-...-` __...-.-.|’_.-'| |-. ._ / _.-' |-._ -._-./ .-’ .-’ |-._-. -.__.-' _.-'_.-'| |-.-._ _.-'_.-' |-._ -._-..-‘.-’ .-’ |-._-. -.__.-' _.-'_.-'| |-.-._ _.-'_.-' |-._ -._-..-‘_.-’ _.-’ -._-..-’ _.-’ -._ _.-'-..-’ Redis 4.0.9 (00000000/0) 64 bit Running in stand alone mode Port: 6379 PID: 55757 http://redis.io @xeraa

Configuration Templates filebeat.autodiscover: providers: - type: docker templates: - condition: equals: docker.container.image: redis config: - type: docker containers.ids: - “${data.docker.container.id}” exclude_lines: [“^\s+[-`(‘.|_]”] @xeraa

Who Logs the Logger Avoid loops Process without -e filebeat.yml: logging.to_files: true @xeraa

Pro: Hot Con: Complexity @xeraa

Orchestrate @xeraa

@xeraa

Where to put Filebeat? DaemonSet @xeraa

https://github.com/elastic/beats/tree/ master/deploy/kubernetes @xeraa

Metadata Either in cluster or not processors: - add_kubernetes_metadata: in_cluster: true - add_kubernetes_metadata: in_cluster: false host: <hostname> kube_config: ${HOME}/.kube/config @xeraa

Metadata { “host”: “172.17.0.21”, “port”: 9090, “kubernetes”: { “container”: { “id”: “382184ecdb385cfd5d1f1a65f78911054c8511ae009635300ac28b4fc357ce51”, “image”: “my-java:1.0.0”, “name”: “my-java” }, “labels”: { “app”: “java”, }, “namespace”: “default”, “node”: { “name”: “minikube” }, “pod”: { “name”: “java-2657348378-k1pnh” } }, } @xeraa

Configuration Templates filebeat.autodiscover: providers: - type: kubernetes templates: - condition: equals: kubernetes.namespace: redis config: - type: docker containers.ids: - “${data.kubernetes.container.id}” exclude_lines: [“^\s+[-`(‘.|_]”] @xeraa

Customize Indices output.elasticsearch: index: “%{[kubernetes.namespace]:filebeat}-%{[beat.version]}-%{+yyyy.MM.dd}” @xeraa

Pro: Hot Con: Complexity++ @xeraa

Moar @xeraa

Index Patterns Time based (default: daily) Versioned @xeraa

Sizing Daily volume x retention x replication @xeraa

Index Lifecycle Management ! ” @xeraa

Frozen Indices https://www.elastic.co/guide/en/elasticsearch/reference/6.6/ frozen-indices.html @xeraa

Conclusion @xeraa

Examples https://github.com/xeraa/java-logging @xeraa

Parse Send Structure Containerize Orchestrate @xeraa

Questions? Philipp Krenn @xeraa @xeraa