精华内容
下载资源
问答
  • nginx 日志输出json格式
    千次阅读
    2022-03-04 10:47:07

    背景

    nginx 默认输出acces日志格式是message格式。现在都做日志统一分析ELK了,message格式就不是很适用了。 所以输出json格式就应用而生了。

    修改 nginx.conf 配置文件, 注释掉之前 log_format 重新写一个 json格式的log_format

    log_format main   '{"@timestamp":"$time_iso8601",'
                        '"@source":"$server_addr",'
                        '"hostname":"$hostname",'
                        '"remote_user":"$remote_user",'
                        '"ip":"$http_x_forwarded_for",'
                        '"client":"$remote_addr",'
                        '"request_method":"$request_method",'
                        '"scheme":"$scheme",'
                        '"domain":"$server_name",'
                        '"referer":"$http_referer",'
                        '"request":"$request_uri",'
                        '"requesturl":"$request",'
                        '"args":"$args",'
                        '"size":$body_bytes_sent,'
                        '"status": $status,'
                        '"responsetime":$request_time,'
                        '"upstreamtime":"$upstream_response_time",'
                        '"upstreamaddr":"$upstream_addr",'
                        '"http_user_agent":"$http_user_agent",'
                        '"http_cookie":"$http_cookie",'
                        '"https":"$https"'
                        '}';
    
    access_log  /var/log/nginx/access.log  main;
    

    重新加载nginx,access日志就是json格式了

    日志输出结果如下:

    {"@timestamp":"2022-03-04T10:15:01+08:00","@source":"172.24.215.134","hostname":"bfdaitidv01","remote_user":"-","ip":"-","client":"10.24.42.162","request_method":"GET","scheme":"http","domain":"localhost","referer":"-","request":"/echo","requesturl":"GET /echo HTTP/1.1","args":"-","size":421,"status": 200,"responsetime":0.000,"upstreamtime":"-","upstreamaddr":"-","http_user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36","http_cookie":"theme_cookie=dark-theme; Admin-Token=eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6Ijc3NDJmMTJiLTI1NjgtNDkyNC05NzYwLTE0MTc4NTkyMjE3YyJ9._nrIszd6ZRjiVjGXSQqra-9i1qbEfNFTBWfv-YQUQEaGzayC5HheGvSWGEuXU8T0uT6CkLWxReLWyQnvoJnEew","https":""}
    
    

    参考资料:
    ngx_http_log_module

    更多相关内容
  • logback 日志输出格式

    千次阅读 2019-09-24 10:36:13
    【前言】 日志对一个系统的重要性不言而喻;日志通常是在排查问题时给人看,一个友好的...下面为大家共享一下通过设置logback日志输出格式,打印出令人欣喜的日志样式。 【搞一下日志格式】 一、未指定日志格...

    强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan

    【前言】

             日志对一个系统的重要性不言而喻;日志通常是在排查问题时给人看,一个友好的输出样式让人看到后赏心悦目,排查效率通常也会随之提高;下面为大家共享一下通过设置logback日志输出格式,打印出令人欣喜的日志样式。

    【搞一下日志格式】

            一、未指定日志格式,日志输出

                  1、代码实现

                      (1)演示日志输出控制器

    /*
     * Copyright (c) 2019. zhanghan_java@163.com All Rights Reserved.
     * 项目名称:实战SpringBoot
     * 类名称:CheckMobileController.java
     * 创建人:张晗
     * 联系方式:zhanghan_java@163.com
     * 开源地址: https://github.com/dangnianchuntian/springboot
     * 博客地址: https://zhanghan.blog.csdn.net
     */
    
    package com.zhanghan.zhboot.controller;
    
    import com.mysql.jdbc.StringUtils;
    import com.zhanghan.zhboot.controller.request.MobileCheckRequest;
    import com.zhanghan.zhboot.properties.MobilePreFixProperties;
    import com.zhanghan.zhboot.util.wrapper.WrapMapper;
    import com.zhanghan.zhboot.util.wrapper.Wrapper;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    @Api(value = "校验手机号控制器", tags = {"校验手机号控制器"})
    public class CheckMobileController {
    
        private static Logger logger = LoggerFactory.getLogger(CheckMobileController.class);
    
        @Autowired
        private MobilePreFixProperties mobilePreFixProperties;
    
        @ApiOperation(value = "优雅校验手机号格式方式", tags = {"校验手机号控制器"})
        @RequestMapping(value = "/good/check/mobile", method = RequestMethod.POST)
        public Wrapper goodCheckMobile(@RequestBody @Validated MobileCheckRequest mobileCheckRequest) {
    
            logger.info("good check mobile param {}", mobileCheckRequest.toString());
    
            String countryCode = mobileCheckRequest.getCountryCode();
            String proFix = mobilePreFixProperties.getPrefixs().get(countryCode);
    
            if (StringUtils.isNullOrEmpty(proFix)) {
                logger.error("good check mobile param is error; param is {}, profix is {}", mobileCheckRequest.toString(), proFix);
                return WrapMapper.error("参数错误");
            }
    
            String mobile = mobileCheckRequest.getMobile();
    
            Boolean isLegal = false;
            if (mobile.startsWith(proFix)) {
                isLegal = true;
            }
    
    
            Map map = new HashMap();
            map.put("mobile", mobile);
            map.put("isLegal", isLegal);
            map.put("proFix", proFix);
            return WrapMapper.ok(map);
        }
    
        @ApiOperation(value = "扩展性差校验手机号格式方式", tags = {"校验手机号控制器"})
        @RequestMapping(value = "/bad/check/mobile", method = RequestMethod.POST)
        public Wrapper badCheckMobile(@RequestBody MobileCheckRequest mobileCheckRequest) {
    
            logger.info("bad check mobile param {}", mobileCheckRequest.toString());
    
            String countryCode = mobileCheckRequest.getCountryCode();
    
            String proFix = "";
            if (countryCode.equals("CN")) {
                proFix = "86";
            } else if (countryCode.equals("US")) {
                proFix = "1";
            } else {
                logger.error("bad check mobile param is error; param is {}, profix is {}", mobileCheckRequest.toString(), proFix);
                return WrapMapper.error("参数错误");
            }
    
            String mobile = mobileCheckRequest.getMobile();
    
            Boolean isLegal = false;
            if (mobile.startsWith(proFix)) {
                isLegal = true;
            }
    
            Map map = new HashMap();
            map.put("mobile", mobile);
            map.put("isLegal", isLegal);
            map.put("proFix", proFix);
            return WrapMapper.ok(map);
        }
    
    }
    

                  2、项目部署服务器后访问打印日志的效果

            二、指定日志格式,日志输出

                  1、代码实现

                      (1)演示日志输出控制器(同上)

                      (2)在项目的resources目录下增加logback.xml设置打印格式,logback.xml内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 说明: 1、日志级别及文件 日志记录采用分级记录,级别与日志文件名相对应,不同级别的日志信息记录到不同的日志文件中 例如:error级别记录到log_error_xxx.log或log_error.log(该文件为当前记录的日志文件),而log_error_xxx.log为归档日志,
    	日志文件按日期记录,同一天内,若日志文件大小等于或大于2M,则按0、1、2...顺序分别命名 例如log-level-2013-12-21.0.log
    	其它级别的日志也是如此。 2、文件路径 若开发、测试用,在Eclipse中运行项目,则到Eclipse的安装路径查找logs文件夹,以相对路径../logs。
    	若部署到Tomcat下,则在Tomcat下的logs文件中 3、Appender FILEERROR对应error级别,文件名以log-error-xxx.log形式命名
    	FILEWARN对应warn级别,文件名以log-warn-xxx.log形式命名 FILEINFO对应info级别,文件名以log-info-xxx.log形式命名
    	FILEDEBUG对应debug级别,文件名以log-debug-xxx.log形式命名 stdout将日志信息输出到控制上,为方便开发测试使用 -->
    <configuration>
        <springProperty scope="context" name="LOG_HOME" source="spring.application.name"/>
    
        <springProfile name="local">
            <property name="LOG_PATH" value="D:/www/logs/common"/> <!-- 日志保存目录 -->
        </springProfile>
        <springProfile name="dev">
            <property name="LOG_PATH" value="/data/logs/common" /> <!-- 日志保存目录 -->
        </springProfile>
    
        <property name="appName" value="common"/>
        <property name="maxSaveDays" value="365"/><!-- 日志最大保存天数 -->
        <property name="maxFileSize" value="200MB"/><!-- 单个文件最大大小 -->
        <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) %green([${LOG_HOME},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %magenta(${PID:-}) %white(---) %-20(%yellow([%20.20thread])) %-55(%cyan(%.32logger{30}:%L)) %highlight(- %msg%n)</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <appender name="rollingFileConsole" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/${appName}-log-console-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
                <maxHistory>${maxSaveDays}</maxHistory> <!--max save days -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${maxFileSize}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) %green([${LOG_HOME},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]) %magenta(${PID:-}) %white(---) %-20(%yellow([%20.20thread])) %-55(%cyan(%.32logger{30}:%L)) %highlight(- %msg%n)</pattern>
                <charset>UTF-8</charset>
            </encoder>
        </appender>
    
        <appender name="rollingFileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/${appName}-log-info-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
                <maxHistory>${maxSaveDays}</maxHistory> <!--max save days -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${maxFileSize}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder>
                <pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"}[%X{userId}|%X{sessionId}][%p][%c{0}-%M]-%m%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>DENY</onMatch>
                <onMismatch>ACCEPT</onMismatch>
            </filter>
        </appender>
    
        <appender name="rollingFileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${LOG_PATH}/${appName}-log-error-%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
                <maxHistory>${maxSaveDays}</maxHistory> <!--max save days -->
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>${maxFileSize}</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder>
                <pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"}[%X{userId}|%X{sessionId}][%p][%c{0}-%M]-%m%n</pattern>
                <charset>UTF-8</charset>
            </encoder>
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
        </appender>    
    
        <!-- 为单独的包配置日志级别,若root的级别大于此级别, 此处级别也会输出 应用场景:生产环境一般不会将日志级别设置为trace或debug,但是为详细的记录SQL语句的情况,
            可将hibernate的级别设置为debug,如此一来,日志文件中就会出现hibernate的debug级别日志, 而其它包则会按root的级别输出日志 -->
        <!-- <logger name="org.springframework" level="DEBUG" /> -->
        <logger name="com.ibatis" level="DEBUG"/>
        <logger name="com.ibatis.common.jdbc.SimpleDataSource" level="DEBUG"/>
        <logger name="com.ibatis.common.jdbc.ScriptRunner" level="DEBUG"/>
        <logger name="com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate"
                level="INFO"/>
        <logger name="java.sql.Connection" level="DEBUG"/>
        <logger name="java.sql.Statement" level="DEBUG"/>
        <logger name="java.sql.PreparedStatement" level="DEBUG"/>
        <logger name="com.netflix.discovery" additivity="true" level="ERROR"/>
        <!-- 生产环境,将此级别配置为适合的级别,以名日志文件太多或影响程序性能 -->
        <root level="INFO">
            <appender-ref ref="rollingFileConsole"/>
            <appender-ref ref="rollingFileInfo"/>
            <appender-ref ref="rollingFileError"/>
            <appender-ref ref="stdout"/>
        </root>
    </configuration>

                  3、项目部署服务器后访问打印日志的效果

                  4、查看日志记录文件,效果也一样,效果图:

            三、项目地址

                     1、地址:https://github.com/dangnianchuntian/springboot

                     2、代码版本:1.5.0-Release

     

    【总结】

            1、通过设定日志格式,输出的样式更加人性化,错误也更加明显;

            2、这个小小的改变,使得在排查程序时更加的赏心悦目,心情上的开心将在无形中增加排错的效率;

    展开全文
  • 近年来,越来越多的同学咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是作者想把这些年积累的经验以文章的形式发出来,让看到文章的同学少走...

    近年来,越来越多的同学咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是作者想把这些年积累的经验以文章的形式发出来,让看到文章的同学少走弯路。K8s 日志系列文章内容偏向落地实操以及经验分享,且内容会随着技术的迭代而不定期更新,本文为该系列文章的第 3 篇。


    作者 | 元乙 阿里云存储服务技术专家

    导读:近年来,越来越多的同学咨询如何为 Kubernetes 构建一个日志系统,或者是来求助在此过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是作者想把这些年积累的经验以文章的形式发出来,让看到文章的同学少走弯路。K8s 日志系列文章内容偏向落地实操以及经验分享,且内容会随着技术的迭代而不定期更新,本文为该系列文章的第 3 篇。
    第一篇:《6 个 K8s 日志系统建设中的典型问题,你遇到过几个?
    第二篇:《一文看懂 K8s 日志系统设计和实践》

    前言

    在上一篇文章《一文看懂 K8s 日志系统设计和实践》中,主要和大家介绍从全局维度考虑如何去构建 K8s 中的日志系统,本文我们将从实践角度出发来一步步构建 K8s 中的日志监控体系。

    构建日志系统的第一步是如何去产生这些日志,而这也往往是最繁杂最困难的一步。

    2009 年阿里云春节上班第一天,在北京一间连暖气都没有的办公室里,一帮工程师一边口呼白气,一边敲出了“飞天”的第一行代码。“飞天”作为阿里云的核心技术平台,其英文名 Apsara——来自吴哥王朝的阿仆萨罗飞天仙女的名字。

    阿里云飞天系统的第一行代码就是为了编写一个日志系统,而现在 apsara logging 的日志库应用在飞天所有的系统中,包括盘古、女娲、伏羲、洛神...

    Kubernetes 中日志重要性

    通常日志最基础的作用是记录程序的运行轨迹,在此之上会衍生出非常多的功能,例如线上监控、告警、运营分析、安全分析等等(详情可以参见第一篇文章《6 个 K8s 日志系统建设中的典型问题,你遇到过几个?),这些功能反过来也对日志具备一定的要求,我们需要尽可能的将日志规范化,以减少收集、解析、分析的代价。

    在 Kubernetes 中,环境的动态性很强,日志基本上都是易失的,因此需要实时将日志采集到中心的存储中,为了配合日志采集,对于日志的输出、采集会有更多的要求。

    下述我们列举了 Kubernetes 中,日志输出的常见注意事项(其中标记 (*)的是 Kubernetes 中特有的项目):

    1. 如何选择日志等级
    2. 日志内容规范
    3. 合理控制日志输出量
    4. 选择多种日志输出目标
    5. 控制日志性能消耗
    6. 如何选择日志库
    7. 日志形态选择(*)
    8. 日志是否落盘以及落盘介质(*)
    9. 如何保证日志存储周期(*)

    如何选择日志等级

    日志等级是用来区分日志对应事件严重程度的说明,这是所有日志中必须具备的一个选项。通常日志会分为 6 个不同的等级:

    • FATAL(致命):用来输出非常严重或预期中不会发生的错误,遇到此种错误应当立即报警并人工介入处理;
    • ERROR (错误):非预期中的错误,此种错误可能导致部分系统异常但不会影响核心业务和系统正常运行;
    • WARN(警告):潜在的危险或值得关注的信息(比较核心的路径);
    • INFO(信息):应用执行过程中的详细信息,一般通过该信息可以看到每个请求的主要执行过程;
    • DEBUG(调试):用于线下调试的日志信息,用于分析应用执行逻辑,线上应用切勿开启;
    • TRACE(跟踪):输出最细致的运行轨迹,可能包含涉及的数据内容。

    作为程序员,一定要合理设置日志等级,个人在开发过程中总结了以下几点经验:

    1. FATAL 类型日志一定是非常严重的错误、需要人工处理的场景打印的;
    2. ERROR 和 WARNING 的区别很多程序员难以选择,可以从告警角度考虑:ERROR 为一般需要告警,WARNING 为不需要;
    3. 日志等级一方面是为了能够表示日志的严重程度,另一方面也是为了控制应用程序的日志输出量,通常线上只能打开 INFO 或 WARN 的日志;
    4. DEBUG 日志可以多打,方便分析问题;
    5. 所有用户请求日志,必须记录;
    6. 对于不确定的外部系统调用,日志需尽可能覆盖周全;
    7. 程序中的日志库需要具备运行期间变更日志等级的能力,方便在遇到问题需要分析时临时更改日志等级;
    8. 通常在新功能上线,涉及的日志可适当提升一个等级,方便实时观察和监控,待稳定后再调整到正常(记得加上注释,方便改回来)。

    日志内容规范

    通常在没有约束的情况下,程序员的发挥天马行空,各种日志内容都会出现,这些只有开发自己才能看懂的日志很难进行分析和告警。因此我们需要一个日志顶向下的规范来约束项目中的开发人员,让所有的日志看起来是一个人打印的而且是易于分析的。

    日志的字段

    日志中通常必备的字段有:Time、Level、Location。对于特定模块/流程/业务,还需要有一些 Common 的字段,例如:

    1. 如果使用 Trace 系统,可以把 TraceID 附加到日志中;
    2. 固定的流程需要附加对应的字段,例如订单的生命周期中,一定要有订单号、用户 ID 等信息,这些信息可以通过 Context 附加到对应流程的日志实例上;
    3. HTTP 请求需要记录:URL、Method、Status、Latency、Inflow、OutFlow、ClientIP、UserAgent 等,详情可以参考 Nginx 日志格式
    4. 如果多个模块的日志都打印到同一个流/文件中,必须有字段标识模块名。

    日志的字段规约最好由运维平台/中间件平台自顶向下推动,约束每个模块/流程的程序员按照规定打印日志。

    日志表现形式

    通常我们建议使用 KeyValue 对形式的日志格式,比如我们阿里的飞天日志库采用的就是这种形式:

    [2019-12-30 21:45:30.611992]    [WARNING]       [958] [block_writer.cpp:671]  path:pangu://localcluster/index/3/prom/7/1577711464522767696_0_1577711517     min_time:1577712000000000       max_time:1577715600000000       normal_count:27595      config:prom     start_line:57315569     end_line:57343195       latency(ms):42  type:AddBlock

    KeyValue 对的日志可以完全自解析且易于理解,同时便于日志采集时自动解析。

    另外推荐的是 JSON 日志格式,支持以 JSON 格式输出的日志库很多,而且大部分的日志采集 Agent 都支持 JSON 格式的日志收集。

    {"addr":"tcp://0.0.0.0:10010","caller":"main.go:98","err":"listen tcp: address tcp://0.0.0.0:10010: too many colons in address","level":"error","msg":"Failed to listen","ts":"2019-03-08T10:02:47.469421Z"}

    注意:绝大部分场景不建议使用非可读的日志格式(例如 ProtoBuf、Binlog 等)。

    单条日志换行问题

    非必要情况下,尽量不要一条日志输出成多行,这种对于采集、解析和索引的代价都比较高。

    合理控制日志输出量

    日志的输出量直接影响到磁盘使用以及对于应用的性能消耗,日志太多不利于查看、采集、分析;日志太少不利于监控,同时在出现问题的时候没办法调查。

    一般线上应用需合理控制日志的数据量:

    1. 服务入口的请求和响应日志没有特殊原因都要输出并采集,采集的字段可以根据需求调整;
    2. 错误日志一般都要打印,如果太多,可以使用采样方式打印;
    3. 减少无效日志输出,尤其是循环中打印日志的情况需尽量减少;
    4. 请求型的日志(比如 Ingress、Nginx 访问日志)一般不超过 5MB/s(500 字节每条,不超过 1W/s),应用程序日志不超过 200KB/s(2KB 每条,不超过 100 条/s)。

    选择多种日志输出目标

    建议一个应用不同类型的日志输出到不同的目标(文件),这样便于分类采集、查看和监控。例如:

    1. 访问日志单独放到一个文件,如果域名不多,可以按照一个域名一个文件的形式;
    2. 错误类的日志单独放一个文件,单独配置监控告警;
    3. 调用外部系统的日志单独放一个文件,便于后续对账、审计;
    4. 中间件通常都由统一的平台提供,日志一般单独打印一个文件。

    控制日志性能消耗

    日志作为业务系统的辅助模块,一定不能影响到业务正常的工作,因此日志模块的性能消耗需要单独额外注意,一般在选择/开发日志库时,需要对日志库进行性能测试,确保正常情况下日志的性能消耗不超过整体 CPU 占用的 5%。

    注意:一定要确保日志打印是异步的,不能阻塞业务系统运行。

    如何选择日志库

    开源的日志库非常多,基本每个语言都有数十种,选择一个符合公司/业务需求的日志库需要精挑细选,有一个简单的指导原则是尽可能使用比较流行的日志库的稳定版本,入坑的几率要小一点。例如:

    1. Java 使用 Log4J、LogBack;
    2. Golang 使用 go-kit
    3. Python 默认集成的日志库大部分场景都够用,建议阅读一下 CookBook
    4. C++ 推荐使用 spdlog,高性能、跨平台。

    日志形态选择

    在虚拟机/物理机的场景中,绝大部分应用都以文件的形式输出日志(只有一些系统应用输出到 syslog/journal);而在容器场景中,多了一个标准输出的方式,应用把日志打到 stdout 或 stderr 上,日志会自动进入到 docker 的日志模块,可以通过 docker logs 或 kubectl logs 直接查看。

    容器的标准输出只适应于比较单一的应用,例如 K8s 中的一些系统组件,线上的服务类应用通常都会涉及到多个层级(中间件)、和各种服务交互,一般日志都会分为好几类,如果全部打印到容器的标准输出,很难区分处理。
    同时容器标准输出对于 DockerEngine 的性能消耗特别大,实测 10W/s 的日志量会额外占用 DockerEngine 1 个核心的 CPU(单核 100%)。

    日志是否落盘以及落盘介质

    在 Kubernetes 中,还可以将日志库直接对接日志系统,日志打印的时候不落盘而直接传输到日志系统后端。这种使用方式免去了日志落盘、Agent 采集的过程,整体性能会高很多。

    这种方式我们一般只建议日志量极大的场景使用,普通情况下还是直接落盘,相比直接发送到后端的方式,落盘增加了一层文件缓存,在网络失败的情况下还能缓存一定的数据,在日志系统不可用的情况下我们的研发运维同学可以直接查看文件的日志,提高整体的可靠性。

    Kubernetes 提供了多种存储方式,一般在云上,都会提供本地存储、远程文件存储、对象存储等方式。由于日志写入的 QPS 很高,和应用也直接相关,如果使用远程类型的存储,会额外多 2-3 次网络通信开销。我们一般建议使用本地存储的方式,可以使用 HostVolume 或者 EmptyDir 的方式,这样对于写入和采集的性能影响会尽可能的小。

    如何保证日志存储周期

    相比传统虚拟机/物理机的场景,Kubernetes 对于节点、应用层提供了强大的调度、容错、缩/扩容能力,我们通过 Kubernetes 很容易就能让应用获得高可靠运行、极致弹性。这些优势带来的一个现象是:节点动态创建/删除、容器动态创建/删除,这样日志也会随时销毁,没办法保证日志的存储周期能够满足 DevOps、审计等相关的需求。

    在动态的环境下实现日志的长期存储只能通过中心化的日志存储来实现,通过实时的日志采集方式,将各个节点、各个容器的日志在秒级内采集到日志中心系统上,即使节点/容器挂掉也能够通过日志还原当时的现场。

    总结

    日志输出是日志系统建设中非常重要的环节,公司/产品线一定要遵循一个统一的日志规范,这样才能保证后续日志采集、分析、监控、可视化能够顺利进行。

    后面的章节会介绍如何为 Kubernetes 规划日志采集和存储的最佳实践,敬请期待。

    阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术圈。”

    阅读全文: http://gitbook.cn/gitchat/activity/5e5f102859549470a2f35fdf

    您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

    FtooAtPSkEJwnW-9xkCLqSTRpBKX

    展开全文
  • log日志输出规范

    千次阅读 2019-08-12 15:16:48
    目录 1、Log的用途 2、记录Log日志的基础原则 2.1、日志级别划分 2.2、日志对性能的影响 2.3、什么时候输出日志...2.4 日志输出的内容 3 日志API规范 3.1Log对象的声明和初始化 3.2不得使用System.out, Sy...

    目录

     

    1、Log的用途

    2、记录Log日志的基础原则

    2.1、日志级别划分

    2.2、日志对性能的影响

    2.3、什么时候输出日志

    2.3.1、系统启动参数、环境变量

    2.3.2、异常捕获

    2.3.3、函数获得期望之外的结果时

    2.3.4、关键操作

    2.4 日志输出的内容

    3 日志API规范

    3.1 Log对象的声明和初始化

    3.2 不得使用System.out, System.err进行日志记录,请改使用logger.debug、logger.error

    3.3 正确的记录异常信息

    3.4 重要方法入口,业务流程前后及处理的结果等,推荐记录log,并使用debug级别

    3.5 不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。

    3.6 Log的内容一定要确保不会因为Log语句的问题而抛出异常造成中断


    1、Log的用途

    不管是使用何种编程语言,日志输出几乎无处不在。总结起来,日志大致有以下几种用途:

    • 问题跟踪:通过日志不仅仅包括我们程序的一些bug,也可以在安装配置时,通过日志可以发现问题。
    • 状态监控:通过实时分析日志,可以监控系统的运行状态,做到早发现问题,早处理问题。
    • 安全审计:审计主要体现在安全方面上,通过日志进行分析,可以发现是否存在非授权的操作。

    2、记录Log日志的基础原则

    2.1、日志级别划分

    Java日志通常可以分为:error、warn、info、debug、trace五个级别。

    • error:问题已经影响到软件的正常运行,并且软件不能自行恢复到正常的运行状态,此时需要输出该级别的错误日志。
    • warn:与业务处理相关的失败,此次失败不影响下次业务的正常执行,通常的结果为外部的输入不能获得期望的结果。
    • info:系统运行期间的系统运行状态变化,或者关键业务处理记录等,用户或者管理员在系统操作运行期间关注的一些信息。
    • debug:软件调试信息,开发人员使用该级别的日志发现程序运行中的一些问题,排查故障。
    • trace:基本同上,但是显示的信息更详尽。

    2.2、日志对性能的影响

    不管多么优秀的日志工具,在日志输出时总会对性能产生或多或少的影响,为了将影响降到对低,有以下几个准则需要遵守:

    • 如何创建Logger实例:创建Logger实例有是否static区别,在log4j的早期版本中,一般会要求使用static,而在高版本以及后来的slf4j中,该问题已经得到优化,获取(创建)logger实例的成本已经很低。所以我们要求:对于可以预见的多数情况下单例运行的class,可以不添加static前缀;对于可能是多例居多,尤其是需要频繁创建的class,要求添加static前缀
    • 判断日志级别:对于可以预见的会频繁产生的日志输出,比如for、while循环,定期执行的job等,建议先使用if对日志级别进行判断后再输出。对于日志输出内容需要复杂的序列化,或输出的某些信息获取成本较高时,需要对日志级别进行判断。比如日志中需要输出用户名,而用户名需要在日志输出时从数据库获取,此时就需要先判断一下日志级别,看看是否有必要获取这些信息。
    • 优先使用参数,减少字符串拼接:使用参数的方式输出日志信息,有助于在性能和代码简洁之间取得平衡。当日志级别限制输出该日志时,参数内容将不会融合到最终输出中,减少了字符串的拼接,从而提升执行效率。

    2.3、什么时候输出日志

    日志并不是越多越详细就越好。在分析运行日志,查找问题时,我们经常遇到该出现的日志没有,无用的日志一大堆,或者有效的日志被大量无意义的日志信息淹没,查找起来非常困难。那么什么时候输出日志呢?以下列出了一些常见的需要输出日志的情况,而且日志的级别基本都是>=INFO,至于Debug级别日志的使用场景,需要具体情况具体分析,但也是要追求“恰如其分”,不是越多越好。

    2.3.1、系统启动参数、环境变量

    系统启动的参数、配置、环境变量、System.Properties等信息对于软件的正常运行至关重要,这些信息的输出有助于安装配置人员通过日志快速定位问题,所以程序有必要在启动过程中把使用到的关键参数、变量在日志中输出出来。在输出时需要注意,不是一股脑的全部输出,而是将软件运行涉及到的配置信息输出出来。比如,如果软件对jvm的内存参数比较敏感,对最低配置有要求,那么就需要在日志中将-Xms -Xmx -XX:PermSize这几个参数的值输出出来。

    2.3.2、异常捕获

    在捕获异常处输出日志,大家在基本都能做到,唯一需要注意的是怎么输出一个简单明了的日志信息。这在后面的问题问题中有进一步说明。

    2.3.3、函数获得期望之外的结果时

    一个函数,尤其是供外部系统或远程调用的函数,通常都会有一个期望的结果,但如果内部系统或输出参数发生错误时,函数将无法返回期望的正确结果,此时就需要记录日志,日志的基本通常是warn。需要特别说明的是,这里的期望之外的结果不是说没有返回就不需要记录日志了,也不是说返回false就需要记录日志。比如函数:isXXXXX(),无论返回true、false记录日志都不是必须的,但是如果系统内部无法判断应该返回true还是false时,就需要记录日志,并且日志的级别应该至少是warn。

    2.3.4、关键操作

    关键操作的日志一般是INFO级别,如果数量、频度很高,可以考虑使用DEBUG级别。以下是一些关键操作的举例,实际的关键操作肯定不止这么多。

    n 删除:删除一个文件、删除一组重要数据库记录……

    n 添加:和外系统交互时,收到了一个文件、收到了一个任务……

    n 处理:开始、结束一条任务……

    n ……

    2.4 日志输出的内容

    •  ERROR:错误的简短描述,和该错误相关的关键参数,如果有异常,要有该异常的StackTrace。
    •  WARN:告警的简短描述,和该错误相关的关键参数,如果有异常,要有该异常的StackTrace。
    •  INFO:言简意赅地信息描述,如果有相关动态关键数据,要一并输出,比如相关ID、名称等。
    •  DEBUG:简单描述,相关数据,如果有异常,要有该异常的StackTrace。

    在日志相关数据输出的时要特别注意对敏感信息的保护,比如修改密码时,不能将密码输出到日志中。 

     

    3 日志API规范

    3.1 Log对象的声明和初始化

    // (推荐)

    private static final Logger logger = LoggerFactory.getLogger(Xxx.class);

     

    private final Logger logger = LoggerFactory.getLogger(getClass());

     

    private  static  final Logger logger =  LoggerFactory.getLogger("loggerName");

     

    private static Logger logger = LoggerFactory.getLogger(Xxx.class);

     

    protected final Logger logger = LoggerFactory.getLogger(getClass());

     

    private Logger logger = LoggerFactory.getLogger(getClass());

     

    protected Logger logger = LoggerFactory.getLogger(getClass());

    3.2 不得使用System.out, System.err进行日志记录,请改使用logger.debug、logger.error

    3.3 正确的记录异常信息

    输出Exceptions的全部Throwable信息,因为logger.error(msg)和logger.error(msg,e.getMessage())这样的日志输出方法会丢失掉最重要的StackTrace信息。

    try {   

        Integer x = null;

        ++x;

    } catch (Exception e) {

        //错误

        log.error(e);       

     

        //错误

        log.error(e, e);       

     

        //错误

        log.error(""+ e);       

     

        //错误

        log.error(e.toString());       

     

        //错误

        log.error(e.getMessage());       

     

        //错误

        log.error(null, e);       

     

        //不推荐

        log.error("", e);       

     

        //错误

        log.error("{}", e);       

     

        //错误

        log.error("{}", e.getMessage());     

       

         //错误

         log.error("Error reading configuration file: " + e);       

     

        //错误

        log.error("Error reading configuration file: "+ e.getMessage());       

     

        //推荐

        log.error("Error reading configuration file", e);

    }

    3.4 重要方法入口,业务流程前后及处理的结果等,推荐记录log,并使用debug级别

    3.5 不允许记录日志后又抛出异常,因为这样会多次记录日志,只允许记录一次日志。

    void foo() throws LogException{

        try{

            // do something

        }catch (Exception e){

            log.error("bad things",e);//错误

            throws new LogException("bad things",e);

        }

    }

    3.6 Log的内容一定要确保不会因为Log语句的问题而抛出异常造成中断

     

    展开全文
  • springboot日志文件,日志输出到文件

    千次阅读 2020-12-30 13:12:11
    日志文件的配置结构:(1)FILE_LOG_PATTERN:日志输出格式变量,在控制台输出和文件中输出的append中都引用了此变量。(2)consoleLog:定义一个控制台的appender(3)fileLog:定义一个日志文件的appender,这就是文件...
  • php如何设置日志输出

    千次阅读 2021-03-23 13:26:34
    php设置日志输出的方法:使用php的写入文件函数,把数据写入到事先定义好的文件中,代码为【file_put_contents(file,data,mode,context)】。php设置日志输出的方法:思想:在想要输出log日志的地方,使用php的写入...
  • 我使用log4j2日志框架后的日志输出格式如下图 下面是使用log4j2日志框架设置日志输出格式的步骤 1、pom.xml文件中添加log4j2依赖,并排除掉spring默认的日志依赖 <dependency> <groupId>org.spring...
  • tomcat 设置日志输出

    千次阅读 2020-12-10 13:54:23
    1 :打开 tomcat bin 目录...后面指定的目录(绝对路径下) 就是自定义输出日志文件地址。gwy.log文件 指定后 在此目录下会自动生成。 2 : 此时 在指定的文件目录下多出一个 gwy.log文件。这个就是全部的日志 ...
  • Android日志[基础篇]Android Log日志输出

    万次阅读 2021-08-19 16:48:43
    android.util.Log输出日志的常用方法如下: Log.v(String tag, String msg) Log.d(String tag, String msg) Log.i(String tag, String msg) Log.w(String tag, String msg) Log.e(String tag, String msg) Log.v...
  • logback-spring kafka日志输出到kafka

    千次阅读 2022-01-28 11:40:15
    <?xml version="1.0" encoding="UTF-8"?> ...-- ConsoleAppender 控制台输出日志 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleApp
  • RocketMQ(08)——日志输出到RocketMQ

    千次阅读 2020-03-10 17:46:58
    日志输出到RocketMQ RocketMQ对常用的几种日志输出框架都定义了一个日志输出实现,使对应的日志信息作为一条消息发送到RocketMQ。要使日志输出信息能够发送到RocketMQ,需要添加rocketmq-logappender依赖。 <...
  • springboot 日志输出到数据库

    千次阅读 2019-12-21 20:04:04
    springboot日志输出到数据库 **************************** logback.xml配置 <appender name="mysql" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logba...
  • Springboot LOG日志输出

    万次阅读 2018-10-25 11:55:06
    开发者:在调试的时候输出日志,可以理解是开发的时候才会使用到,实际用户在run状态下是看不到这个输出信息的。 Info 用户:在运行状态下输出日志,最终用户使用的,这部分属于系统的日志功能。 Warn 警告,应该...
  • 日志输出到Docker容器外

    千次阅读 2021-01-14 03:59:22
    1.1 使用 Docker 容器日志我们可以利用 docker ...docker logs 会监控容器中操作系统的标准输出设备(STDOUT),一旦 STDOUT 有数据产生,就会将这些数据传输到另一个“设备”中,该 Docker 的被称为“日志驱动(Loggin...
  • -- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 --> <!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通
  • django线上环境中的日志输出是相当重要的,它可以将所有的错误、警告、调试等重要信息全部输出到日志,这样便于维护和排查问题。 接下来本文会详细的介绍django logging配置,以及这些配置的含义与作用。 用到的...
  • MybatisPlus设置日志输出

    千次阅读 2020-05-24 22:37:45
    在上一篇的基础上,我们启动日志输出,方便测试。 开启mybatis-plus日志 在application.properties文件中设置日志,并指定设置什么日志,这里我使用的是标准输出日志。 注:有些日志需要你导入jar包再...
  • 在idea的控制台很难看到日志,很快速的就刷过去了,而且日志多的话,很多就看不到了,所以我设置了一下idea把日志输出到文件,方便查看: 1.在idea的菜单栏,找到这个向下的三角,点击,选择Edit Configurations ...
  • Tomcat关闭日志输出

    千次阅读 2019-07-23 16:18:45
    一般在部署Tomcat后,运行久了,catalina.out文件会越来越大,对系统...那么Tomcat怎么关闭日志输出? 一、 linux 系统 1、直接修改catalina.sh文件的输出语句 在文件中找到以下内容: [java]view plaincopy ...
  • mybatis 配置日志输出

    千次阅读 2019-10-26 15:24:20
    首先,导入日志架包 配置log4j.properties文件 log4j.rootLogger=DEBUG,Console #DEBUG:级别 Console:输出到控制台 log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=...
  • Spring Boot 修改日志输出等级

    千次阅读 2021-02-05 17:43:37
    日志的级别如下 TRACE < DEBUG < INFO <...修改根级别的日志输出等级 logging.level.root=warn 也可以设置包级别的日志 logging.level.org.springframework.web=debug 此时包名为 org
  • 用上篇博客部署Java程序是ok的,不过Java日志打印在容器里,不能满足原来ELK的日志搜集。...1、首先 Dockerfile 里的ENTRYPOINT配置Java日志输出无果 # 基础镜像使用Java FROM java:8 LABEL name=shop-client-prod..
  • log4j2 自定义日志输出文件

    千次阅读 2019-08-13 15:21:18
    最近用到一个项目,需要在一个类中,将日志区分打印到不同的日志文件中 比如同一个地方打印两条日志“receive message from port[123]”,"receive message from port[456]" 这两条日志的内容一样的,只不过里面的...
  • tomcat终端查看实时日志输出

    千次阅读 2019-05-08 16:26:40
    进入tomcat中的logs目录,并键入命令:tail -f catalina.out,如下图所示: 结果显示: 退出:Ctrl+C;
  • Postgres 设置日志输出内容

    千次阅读 2020-04-27 19:05:27
    Postgres 设置日志输出内容 目录 修改方法 方法一、修改配置文件 方法二、修改系统设置 查看日志配置 关于日志级别 关于日志中文乱码 程序运行时出现了错误,但是无法判断是哪个SQL造成的,因此修改...
  • springboot日志输出到文件

    万次阅读 多人点赞 2018-04-25 16:49:01
    过去我对日志很不在意,该有的日志没有,不该有的日志却随意输出。新换的工作,上司对日志有严格的要求,也就慢慢开始注意了。 一般而言,一个接口或者说一段程序,其入口要有日志,记录传入的数据是什么;部分重要...
  • log4j的详细配置,log4j.xml和log4j.properties,日志输出到文件,邮件,数据库,控制台等
  • ansible 日志输出技巧

    千次阅读 2020-06-16 15:40:58
    -vvv or -vvvv 输出详细信息 ansible -i hosts all -m setup -vvv playbook 和 Ad-hoc 都可以用 playbook输出某个task 的执行结 register 配合 debug可以输出某个task 的执行结果 - name: "启动{{item.port}}...
  • Filebeat 日志输出至 Kafka

    千次阅读 2020-08-03 18:19:11
    Filebeat 是一款轻量级的日志采集器,可以用来收集日志,...通过 filebeat 配置文件 filebeat.yml 指定需要收集的日志,并指定输出至 elasticsearch,logstash,kafka,redis 等。 本文讲述如何配置 filebeat,将日志

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 746,949
精华内容 298,779
关键字:

日志输出