java日志规范及模板

2023-01-30  本文已影响0人  伊丽莎白菜

日志规约

  1. 【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架(如SLF4J)中的 API,使用门面模式的日志框架,有利于维护和各个类的日志处理 方式统一。

  2. 【强制】日志文件至少保存 15 天,因为有些异常具备以“周”为频次发生的特点。对于当天日志,以 “应用名.log”来保存,保存在/{统一目录}/logs/{应用名}目录下,过往日志文件名带有yyyy-MM-dd格式日期。

  3. 【强制】在日志输出时,字符串变量之间的拼接使用占位符的方式。 说明:因为 String 字符串的拼接会使用 StringBuilder 的 append() 方式,有一定的性能损耗。使用占位符仅是替换动 作,可以有效提升性能。
    正例logger.debug("Processing trade with id : {} and symbol : {}", id, symbol);

  4. 【强制】生产环境禁止使用 System.out 或 System.err 输出或使用 e.printStackTrace() 打印异常堆栈。

  5. 【强制】异常信息应该包括两类信息:案发现场信息和异常堆栈信息。如果不处理,那么通过关键字 throws 往上抛出。

    注意:一定要携带最后一个参数e(java.lang.Throwable),禁止仅打印 e.getMessage()

    正例logger.error("inputParams: {}", 各类参数或者对象 toString(), e);

  6. 【推荐】谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时 删除这些观察日志。

日志格式

统一的日志格式不仅对用户友好,也有利于日志收集等运维平台做进一步处理。因此,日志格式必须在系统内达成共识。

一条完整的日志由系统自动捕获的公共信息(由日志模板定义),和开发者手动记录的日志信息拼接组成,即一条日志=公共信息+日志体

格式定义

以下日志格式配置适用于log4j2与logback,对应xml中的pattern配置:

|%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{traceId}|%X{spanId}|${appName}|%t|%C|%M|%L|%m%n

分段释义:

|日期时间|日志级别|链路ID|链路跨度ID|应用名词|线程名称|类名|方法名|行号|日志体

其中traceId与spanId是链路追踪参数,需要基于链路追踪框架生成,可以结合链路追踪系统使用;appName由应用系统定义。

日志样例

ELK配置

filebeat

每台服务器运行一个filebeat即可,负责采集日志并发送到logstash:

注意tags表示所属项目,最终会对应到elasticsearch的不同索引。

#=========================== Agent name =============================
name: 100.127.6.231
#=========================== Filebeat inputs =============================

filebeat.inputs:

- type: log

  # Change to true to enable this input configuration.
  enabled: true

  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    - /apps/logs/iot/*/app.log

  # The regexp Pattern that has to be matched. The example pattern matches all lines starting with [
  multiline.pattern: ^\|

  # Defines if the pattern set under pattern should be negated or not. Default is false.
  multiline.negate: true

  # Match can be set to "after" or "before". It is used to define if lines should be append to a pattern
  # that was (not) matched before or after or as long as a pattern is not matched based on negate.
  # Note: After is the equivalent to previous and before is the equivalent to to next in Logstash
  multiline.match: after
  tags: ['iot']
- type: log
  enabled: true
  paths:
    - /apps/logs/lms/lms-*.log
  multiline.pattern: ^\|
  multiline.negate: true
  multiline.match: after
  tags: ['lms']

#============================= Filebeat modules ===============================

filebeat.config.modules:
  # Glob pattern for configuration loading
  path: ${path.config}/modules.d/*.yml

  # Set to true to enable config reloading
  reload.enabled: false

#==================== Elasticsearch template setting ==========================

setup.template.settings:
  index.number_of_shards: 1

#============================== Dashboards =====================================
setup.kibana:

#----------------------------- Logstash output --------------------------------
output.logstash:
  # The Logstash hosts
  hosts: ["192.168.3.39:5044","192.168.3.214:5044"]

#================================ Processors =====================================

# Configure processors to enhance or manipulate events generated by the beat.

processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~
  - add_docker_metadata: ~
  - add_kubernetes_metadata: ~

logstash

# Sample Logstash configuration for creating a simple
# Beats -> Logstash -> Elasticsearch pipeline.

input {
  beats {
    port => 5044
  }
}

filter {
    if "iot" in [tags] {
        mutate { add_field => { "[@metadata][target_index]" => "iot-%{+YYYY.MM.dd}" } }
    } else if "lms" in [tags] {
        mutate { add_field => { "[@metadata][target_index]" => "lms-%{+YYYY.MM.dd}" } }
    } else {
        mutate { add_field => { "[@metadata][target_index]" => "default-%{+YYYY.MM.dd}" } }
    }
    
    grok {
        match => { "message" => "\|%{DATA:datetime}\|%{NOTSPACE:level}\s?\|%{DATA:traceId}\|%{DATA:spanId}\|%{DATA:app}\|%{NOTSPACE:thread}\|%{NOTSPACE:class}\|%{NOTSPACE:method}\|%{INT:line}\|(?<content>(.|\n)*)" }
        # 移除一些不太有用的默认字段
        remove_field => ["[agent][ephemeral_id]","[agent][id]","[agent][id]","[agent][type]","[agent][version]","[host][mac]","[host][ip]","[host][id]","[host][architecture]","[host][containerized]","[host][os][codename]","[host][os][family]","[host][os][name]","[host][os][kernel]","[ecs][version]"]
    }
}

output {
  elasticsearch {
    hosts => ["http://192.168.0.184:9200","http://192.168.0.182:9200","http://192.168.0.59:9200"]
    index => "%{[@metadata][target_index]}"
    user => "elastic"
    password => "*********"
  }
}

参考文献

上一篇下一篇

猜你喜欢

热点阅读