精华内容
下载资源
问答
  • ELK/ELFK(7.3 ) 企业PB级日志系统实战

    千人学习 2019-12-25 11:42:57
    Elastic Stack日志系统是目前企业应用广泛的一套日志解决方案。   包含的组件有Filebeat,Logstash,Elastic,Kibana等 本堂课引入Kafka 让Elastic Stack 能适应企业PB级的业务日志量 并弥补传统ELk架构的不足 &...
  • 真正通用的操作日志系统设计

    热门讨论 2011-08-12 09:31:42
    真正通用的操作日志系统设计,这个是以前看到的资料,觉得不错。此文档版权属于作者本人“加伊”。
  • Loki日志系统

    千次阅读 2020-06-22 15:51:00
    Loki的第一个稳定版本于2019年11月19日发布,是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。 Grafana 对 Loki 的描述如下: Loki: like Prometheus, but for logs. Loki...

    一、概述

    背景

    Loki的第一个稳定版本于2019年11月19日发布,是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。 Grafana 对 Loki 的描述如下:

    Loki: like Prometheus, but for logs. Loki is a horizontally-scalable, highly-available, multi-tenant log aggregation system inspired by Prometheus. It is designed to be very cost effective and easy to operate. It does not index the contents of the logs, but rather a set of labels for each log stream.

     

    简单说,Loki 是专门用于聚集日志数据,重点是高可用性和可伸缩性。与竞争对手不同的是,它确实易于安装且资源效率极高。

    血衫目前运维大概上百个节点,虽然系统是统一的基线版本且使用docker运行应用,平时相安无事,但变更后的问题排查仍有点心有余悸。对一个火热的日志系统elk也有浅尝辄止,奈何对于非核心应用,多耗散一份算力意味着成本增加和利润的减少,elk对于小团队来说,还是过于笨重。趁着近日的疫情无法外出,调研后将 Loki 上线了生产,可以说是完美契合了中小团队对日志平台的需求。

    介绍

    与其他日志聚合系统相比,Loki具有下面的一些特性:

    • 不对日志进行全文索引(vs ELK技)。通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成本。
    • 通过使用与 Prometheus 相同的标签记录流对日志进行索引和分组,这使得日志的扩展和操作效率更高。
    • 特别适合储存 Kubernetes Pod 日志; 诸如 Pod 标签之类的元数据会被自动删除和编入索引。
    • 受 Grafana 原生支持。

    Loki 由以下3个部分组成:

    • loki是主服务器,负责存储日志和处理查询。
    • promtail是代理,负责收集日志并将其发送给 loki 。
    • Grafana用于 UI 展示。

     

    二、安装

    本文以一台centos 7.6主机来演示一下loki,ip地址为:192.168.31.229 

     

    Docker-compose.yml 可以参考Loki文档介绍,开箱即用。

    创建目录/opt/loki,文件结构如下:

    ./
    └── docker-compose.yaml

     

    docker-compose.yaml

    version: "3"
    
    networks:
      loki:
    
    services:
      loki:
        image: grafana/loki:latest
        ports:
          - "3100:3100"
        networks:
          - loki
    
      promtail:
        image: grafana/promtail:latest
        networks:
          - loki
    
      grafana:
        image: grafana/grafana:master
        ports:
          - "3000:3000"
        networks:
          - loki

    说明:这里启动了3个容器,都是运行在网桥loki上,方便相互通讯。

     

    然后直接使用 docker-compose 启动即可:

    docker-compose up -d

     

    查看服务状态

    # docker-compose ps
         Name                    Command               State           Ports         
    ---------------------------------------------------------------------------------
    loki_grafana_1    /run.sh                          Up      0.0.0.0:3000->3000/tcp
    loki_loki_1       /usr/bin/loki -config.file ...   Up      0.0.0.0:3100->3100/tcp
    loki_promtail_1   /usr/bin/promtail -config. ...   Up 

     

    二、使用

    安装完成后,访问节点的 3000 端口访问 grafana,默认用户名和密码都是admin

    http://192.168.31.229:3000/

     

    选择添加数据源:

     

     选择loki

     

     

    源地址配置http://loki:3100即可

     

    注意:这里的 http://loki:3100,表示访问容器名为loki的3100端口。

     

    点击保存

     

     

    保存完成后,切换到 grafana 左侧区域的Explore

     

     

    即可进入到Loki的页面

     

     

    点击Log labels就可以把当前系统采集的日志标签给显示出来,可以根据这些标签进行日志的过滤查询:

    选择job-->varlogs

     

     点击右上角的Run Query,效果如下:

     

     这里展示的是promtail容器里面/var/log目录中的日志

    promtail容器/etc/promtail/config.yml 

    server:
      http_listen_port: 9080
      grpc_listen_port: 0
    
    positions:
      filename: /tmp/positions.yaml
    
    clients:
      - url: http://loki:3100/loki/api/v1/push
    
    scrape_configs:
    - job_name: system
      static_configs:
      - targets:
          - localhost
        labels:
          job: varlogs
          __path__: /var/log/*log

    这里的job就是varlog,文件路径就是/var/log/*log

     

    四、配置

    从上面的步骤已经可以一窥使用方法了,如果要使用起来,我们还需要了解如下信息:

    Loki 的配置

    Loki的详细配置,可查看官方文档:https://github.com/grafana/loki/blob/master/docs/README.md

    配置相关文档: https://github.com/grafana/loki/blob/v1.3.0/docs/configuration/README.md

    我目前均保留了保留默认配置。

    promtail的配置

    promtail 是 Loki 的官方支持的日志采集端,在需要采集日志的节点上运行采集日志,再统一发送到 Loki 进行处理。我们编写的大多是这一部分。

    官方配置说明: https://github.com/grafana/loki/blob/v1.3.0/docs/clients/promtail/configuration.md

    除了使用Promtail,社区还有很多采集日志的组件,比如fluentd、fluent bit等,都是比较优秀的。

     

    五、选择器

    对于查询表达式的标签部分,将其包装在花括号中{},然后使用键值对的语法来选择标签,多个标签表达式用逗号分隔,比如:

    {app="mysql",name="mysql-backup"}

    目前支持以下标签匹配运算符:

    • =等于
    • !=不相等
    • =~正则表达式匹配
    • !~不匹配正则表达式

    比如:

    {name=~"mysql.+"}
    {name!~"mysql.+"}

    适用于Prometheus标签选择器规则同样也适用于Loki日志流选择器。

     

    六、过滤器

    编写日志流选择器后,您可以通过编写搜索表达式来进一步过滤结果。搜索表达式可以只是文本或正则表达式。
    查询示例:

    {job="mysql"} |= "error"
    {name="kafka"} |~ "tsdb-ops.*io:2003"
    {instance=~"kafka-[23]",name="kafka"} != kafka.server:type=ReplicaManager

     

    过滤器运算符可以被链接,并将顺序过滤表达式-结果日志行将满足每个过滤器。例如:

    {job="mysql"} |= "error" != "timeout"

    已实现以下过滤器类型:

    • |= 行包含字符串。
    • != 行不包含字符串。
    • |~ 行匹配正则表达式。
    • !~ 行与正则表达式不匹配。
      regex表达式接受RE2语法。默认情况下,匹配项区分大小写,并且可以将regex切换为不区分大小写的前缀(?i)。

    更多内容可参考官方说明

     

    举例,我需要查询包含关键字packages

    {job="varlogs"}  |= "packages"

    效果如下:

     

     

    参考资料

     

    本文参考链接:

    https://blog.kelu.org/tech/2020/01/31/grafana-loki-for-logging-aggregation.html

    https://www.cnblogs.com/ssgeek/p/11584870.html

     

    展开全文
  • syslog日志系统——日志采集

    万次阅读 2018-11-08 14:00:17
    客户端埋点就是在客户系统植入日志发送的代码,可以是前端页面、app界面、后端服务等,把需要的日志信息发送到指定的日志采集接口。 日志的发送应该采用异步方式,这样不会对客户系统代码的执行造成影响。 日志采集 ...

    日志采集的流程

    日志采集流程

    客户端埋点

    客户端埋点就是在客户系统植入日志发送的代码,可以是前端页面、app界面、后端服务等,把需要的日志信息发送到指定的日志采集接口。
    日志的发送应该采用异步方式,这样不会对客户系统代码的执行造成影响。

    日志采集

    日志采集接口把接收过来的日志数据写入到日志文件,日志文件以天为单位进行存储。

    日志采集接口代码

    接口采用@IgnoreToken标记不需要进行令牌校验。
    采用@CrossOrigin标记,让接口能够跨域访问,支持AJAX跨域请求。

        @ApiOperation(value = "提交日志")
        @ApiImplicitParams({
                @ApiImplicitParam(name = "logData", value = "日志数据", dataType = "LogData", paramType = "body")
        })
        @RequestMapping(path = "/log/add", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
        @IgnoreToken
        @CrossOrigin
        public ResponseData addLog(@RequestBody LogData logData) {
    
            String logID = logService.logToFile(logData);
    
            return ResponseData.success(logID);
        }
    

    日志文件格式的设计

    日志以文本格式保存,每条日志按行写入。
    日志行的格式如下:

    时间戳|日志ID|日志数据JSON
    

    日志格式截图
    日志按行保存的好处是,可以利用BufferedReader的readLine方法进行日志的按行读取。
    日志按行保存,要对日志数据JSON部分进行处理,把换行符替换掉。

    日志按行保存的主要代码

        public String logToFile(LogData logData){
            LogGroupData groupData = getLogGroup(logData.getKey());
            logData.setGroupID(groupData.getGroupID());
    
            String date = ConvertUtil.formatDate(new Date(), "yyyyMMdd");
            String path = PathUtil.combine(logFolder, "LOG" + date + ".log");
    
            String uuid = UUID.randomUUID().toString();
            String json = JSON.toJSONString(logData);
    
            StringBuilder sb = new StringBuilder();
            sb.append("[" + ConvertUtil.formatDate(new Date()) + "]|");
            sb.append(uuid + "|");
            for (int i = 0; i < json.length(); i++) {
                char c = json.charAt(i);
                if (c == '\r' || c == '\n')//换行符替换为空格
                    sb.append(" ");
                else
                    sb.append(c);
            }
    
            FileUtil.appendLine(path, sb.toString());
    
            return uuid;
        }
    

    日志写入文件的主要代码

    利用RandomAccessFile类写入,用文件琐控制并发。如果是海量日志的场合,可以部署多几个采集点。

        public static void appendLine(String path, String line) {
    
            RandomAccessFile fout = null;
            FileChannel channel = null;
            try {
                File file = new File(path);
                if (!file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
                byte[] bytes = line.getBytes("utf-8");
                fout = new RandomAccessFile(file, "rw");
                long filelength = fout.length();//获取文件的长度
                fout.seek(filelength);//将文件的读写指针定位到文件的末尾
                channel = fout.getChannel();//打开文件通道
                FileLock fileLock = null;
                while (true) {
                    try {
                        fileLock = channel.tryLock();//不断的请求锁,如果请求不到,等一秒再请求
                        break;
                    } catch (Exception e) {
                        logger.error("[FileUtil.appendLine]请求琐失败。");
                        Thread.sleep(1000);
                    }
                }
                fout.write(bytes);
                fout.writeChar('\n');
                fileLock.release();
                channel.close();
                fout.close();
    
            } catch (Exception e1) {
                logger.error(e1.getMessage(), e1);
            } finally {
                IOUtil.close(channel);
                IOUtil.close(fout);
            }
        }
    

    日志汇总

    通过定时任务,把各个采集点的日志文本导入数据库/大数据存储。

    展开全文
  • 日志系统之Flume日志收集

    千次阅读 2015-06-06 21:17:49
    本文介绍在日志系统中如何使用flume agent做日志收集以及为了满足我们的需求对flume agent进行了哪些扩展。

    最近接手维护一个日志系统,它用于对应用服务器上的日志进行收集然后提供实时分析、处理并最后将日志存储到目标存储引擎。针对这三个环节,业界已经有一套组件来应对各自的需求需求,它们是flume+kafka+hdfs/hbase。我们在实时分析、存储这两个环节,选择跟业界的实践相同,但agent是团队自己写的,出于对多种数据源的扩展需求以及原来收集日志的方式存在的一些不足,于是调研了一下flume的agent。结果是flume非常契合我们的实际需求,并且拥有良好的扩展性与稳定性。于是打算采用flume的agent替换我们原先的实现。

    本文介绍我们如何使用flume agent以及为了满足我们的需求进行了哪些扩展。备注:全文所指的flume均指flume-ng,版本基于1.6.0。

    flume简介

    flume 通过Agent对各个服务器上的日志进行收集,它依赖三大核心组件,它们分别是:source,channel,sink。它们之间的串联关系如下图:


    之间的关系也比较简单:source负责应对各种数据源进行日志收集;channel负责日志的中间暂存,将日志收集跟日志发送解耦;sink负责日志的发送,将日志发送到目的地。更详细的讲解,请移步官网。下面谈谈,我们对flume的使用与扩展。

    Source的扩展

    Flume提供了一个基于跟踪文件夹内“文件个数”变动的source称之为Spool Directory Source。它跟踪目标日志文件夹,当有新的日志文件产生时就会触发对新日志文件的收集,但它不支持日志文件的追加。也就是说一旦它开始收集某个日志文件,那么这个日志文件就不能再被编辑,如果在读取日志文件的时候,日志文件产生了变动那么它将会抛出异常。也就是说,当收集到当日日志文件时,同时又有新的日志在往里面写入时,该source是不适合这种需求的。

    如果你的需求是接近“准实时”的日志收集并且你非要用这个souce,应对的方案是:你只能选择将应用程序的日志框架(比如常用的log4j)的appender的“滚动机制”设置为按分钟滚动(也就是每分钟产生一个新日志文件)。这种机制不是不可行,但有些不足的地方,比如日志文件过多:当日志除了要被日志系统收集,还需要本地保留时,这种机制将非常难以接受。

    我们希望日志文件按天滚动产生新的日志文件,当天的日志以追加的方式写入当天的日志文件并且Agent还要能够以接近实时的速度收集新产生的日志(追加)的。如果agent挂掉或者服务器宕机,日志文件不能丢失,agent能够自动跨日期收集。其实,spooling directory source已经为我们的实现提供了模板,但要进行一些改造,主要是以下几点:

    (1)原先的Spooling Directory Source不支持对收集的日志文件的内容进行追加:


    如果文件有任何改动,将以异常的形式抛出。此处需要移除异常

    (2)对当日日志文件进行持续监控

    原先的实现,当获取不到event直接删除或者重命名当前文件,并自动混动到下一个文件:

    /* It's possible that the last read took us just up to a file boundary.
         * If so, try to roll to the next file, if there is one. */
        if (events.isEmpty()) {
          retireCurrentFile();
          currentFile = getNextFile();
          if (!currentFile.isPresent()) {
            return Collections.emptyList();
          }
          events = currentFile.get().getDeserializer().readEvents(numEvents);
        }

    修改后的实现,当当前文件不是当天的日志文件时才处理当前文件并自动滚动到下一个文件,如果是当日文件,则继续跟踪:

    if(!isTargetFile(currentFile) 		//	Only CurrentFile is no longer the target, at the meanwhile, next file exists.
    	    && (isExistNextFile()) ){	//	Then deal with the history file(ever target file)
      logger.info("File:{} is no longer a TARGET File, which will no longer be monitored.", currentFile.get().getFile().getName());
      retireCurrentFile();
      currentFile = getNextFile();
    }

    flume 该source的源码见: github

    另外此处,我们判断是否是目标文件(当日日志文件)的处理方式是比对服务器日期跟文件名中包含的日期是否一致:

    private boolean isTargetFile(Optional<FileInfo> currentFile2) {
    		
      String inputFilename = currentFile2.get().getFile().getName();
      SimpleDateFormat dateFormat = new SimpleDateFormat(targetFilename);
      String substringOfTargetFile = dateFormat.format(new Date());
    		
      if(inputFilename.toLowerCase().contains(substringOfTargetFile.toLowerCase())){
        return true;
      }
    		
      return false;
    }

    所以在新的配置里还需要加入日期格式的配置,通常是:yyyy-MM-dd。

    Sink 的扩展

    Sink在Flume的agent组件中充当数据输出的作用。在flume之前的版本(1.5.2)中已经对多个数据持久化系统提供了内置支持(比如hdfs/HBase等),但默认是没有kafka的。如果我们想将日志消息发送到kafka,就需要自己扩展一个kafkaSink。后来通过搜索发现在最新的stable release版本:1.6.0中,官方已经集成了kafkaSink。不过1.6.0是5月20号刚刚发布,官方的Download页面以及User Guide还没有进行更新,所以请在版本列表页面下载1.6.0版本。在下载到的安装包内有最新的KafkaSink介绍。

    核心的配置有:brokerList(为了高可用性,flume建议至少填写两个broker配置)、topic。详见列表:


    出于好奇心,在github上大概浏览了官方实现kafkaSink的源码,发现Event的Header部分并没有被打包进消息发送走:

            byte[] eventBody = event.getBody();
            Map<String, String> headers = event.getHeaders();
    
            if ((eventTopic = headers.get(TOPIC_HDR)) == null) {
              eventTopic = topic;
            }
    
            eventKey = headers.get(KEY_HDR);
    
            if (logger.isDebugEnabled()) {
              logger.debug("{Event} " + eventTopic + " : " + eventKey + " : "
                + new String(eventBody, "UTF-8"));
              logger.debug("event #{}", processedEvents);
            }
    
            // create a message and add to buffer
            KeyedMessage<String, byte[]> data = new KeyedMessage<String, byte[]>
              (eventTopic, eventKey, eventBody);
            messageList.add(data);

    这一点,可能并不满足我们的需求:我们需要消息头里的信息成为消息的一部分,然后在storm里针对header信息进行一些处理。比如:

    (1)我们会默认在头里加入产生日志的服务器的Host,以便对日志进行分流或对没有存储host的日志进行“补偿”

    (2)我们会默认在头里加入日志类型的标识,以便区分不同的日志并分流到不同的解析器进行解析

    因为日志的来源以及形式是多样的,所以header里这些携带的信息是必要的。而flume官方的KafkaSink却过滤掉了header中的信息。因此,我们选择对其进行简单的扩张,将Event的header跟body打包成一个完整的json对象。具体的实现:

        private byte[] generateCompleteMsg(Map<String, String> header, byte[] body) {
            LogMsg msg = new LogMsg();
            msg.setHeader(header);
            msg.setBody(new String(body, Charset.forName("UTF-8")));
    
            String tmp = gson.toJson(msg, LogMsg.class);
            logger.info(" complete message is : " + tmp);
            return tmp.getBytes(Charset.forName("UTF-8"));
        }

                    // create a message and add to buffer
                    KeyedMessage<String, byte[]> data = new KeyedMessage<String, byte[]>
                        (eventTopic, eventKey, generateCompleteMsg(headers, eventBody));
                    messageList.add(data);

    Interceptor使用

    上面提到日志的源以及格式多种多样,我们不可能将所有工具、组件的日志格式按照我们想要的方式作格式化,特别是一些封闭的组件或线上的系统。很显然source跟sink只负责日志的收集和发送,并不会区分日志内容。而flume提供的Interceptor这一功能,给flume提供了更强大的扩展性。而我们拦击日志,并给其添加特定的header就是通过flume内置的几个interceptor实现的。我们应用了这么几个interceptor:

    (1)host:往header中设置当前主机的Host信息;

    (2)static:往header中设置一个预先配好的key-value对,我们用它来鉴别不同的日志源

    (3)regex:通过将Event的body转换成一个UTF-8的字符串,然后匹配正则表达式,如果匹配成功,则可以选择放行或者选择删除

    前两个interceptor我们之前已经提及过它的用途,而第三个我们用它来匹配日志中是否存在“DEGUG”字样的tag,如此存在,则删除该日志(这个是可选的)。

    Selector 的使用

    目前没有使用Selector的需求,不过它的用途也很常见:它可以用来选择Channel,如果你有多个Channel,并且是有条件得选择性发送的情况下,可以使用Selector来提高日志收集的灵活性。比如:如果你需要将不同不同日志源的日志发往不同的目的地可以建立多个channel然后按一定的规则来匹配,这里主要用到Multiplexing Channel Selector

    展开全文
  • 摘要:本节主要来讲解Android10.0 日志系统的logd、logcat相关指令说明、日志分类和常用日志属性 阅读本文大约需要花费15分钟。 文章首发微信公众号:大猫玩程序 专注于Android系统级源码分析,Android的平台...

    摘要:本节主要来讲解Android10.0 日志系统的logd、logcat相关指令说明、日志分类和常用日志属性

    阅读本文大约需要花费15分钟。

    文章首发微信公众号:IngresGe

    专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

    欢迎关注我的公众号!

    [Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

    [Android取经之路] 系列文章:

    《系统启动篇》

    1. Android系统架构
    2. Android是怎么启动的
    3. Android 10.0系统启动之init进程
    4. Android10.0系统启动之Zygote进程
    5. Android 10.0 系统启动之SystemServer进程
    6. Android 10.0 系统服务之ActivityMnagerService
    7. Android10.0系统启动之Launcher(桌面)启动流程
    8. Android10.0应用进程创建过程以及Zygote的fork流程
    9. Android 10.0 PackageManagerService(一)工作原理及启动流程
    10. Android 10.0 PackageManagerService(二)权限扫描
    11. Android 10.0 PackageManagerService(三)APK扫描
    12. Android 10.0 PackageManagerService(四)APK安装流程

    《日志系统篇》

    1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
    2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
    3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
    4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

    《Binder通信原理》

    1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
    2. Android10.0 Binder通信原理(二)-Binder入门篇
    3. Android10.0 Binder通信原理(三)-ServiceManager篇
    4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
    5. Android10.0 Binder通信原理(五)-Binder驱动分析
    6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
    7. Android10.0 Binder通信原理(七)-Framework binder示例
    8. Android10.0 Binder通信原理(八)-Framework层分析
    9. Android10.0 Binder通信原理(九)-AIDL Binder示例
    10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
    11. Android10.0 Binder通信原理(十一)-Binder总结

      《HwBinder通信原理》

    1. HwBinder入门篇-Android10.0 HwBinder通信原理(一)
    2.  HIDL详解-Android10.0 HwBinder通信原理(二)
    3. HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
    4. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
    5. HwServiceManager篇-Android10.0 HwBinder通信原理(五)
    6. Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
    7. Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
    8. JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
    9. JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
    10. HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
    11. HwBinder原理总结-Android10.0 HwBinder通信原理(十一)

    《编译原理》

    1. 编译系统入门篇-Android10.0编译系统(一)
    2. 编译环境初始化-Android10.0编译系统(二)
    3. make编译过程-Android10.0编译系统(三)
    4. Image打包流程-Android10.0编译系统(四)
    5. Kati详解-Android10.0编译系统(五)

    1.概述

        在程序开发中,日志是必不可少的一个调试手段,Android的开发亦是如此。

        在Android的开发中,我们是通过LOGD\SLOGD等方式进行日志的写入,然后通过 logcat 读取相关的日志,但是日志是如何写入和读取的,底层的操作是什么,有时候没有深入研究。

        本节重点从底层源码级来分析一下Android的日志读写原理。

       在Android5.0(Android-L)之前,log由kernel的环形 buffer 保存,在Android5.0 之后,log保存在用户空间,通过Socket进行访问。

        在Android5.0之后,引入了Logd的守护进程用来进行日志的读写操作。

    早期的Kernel ring buffer的原理可以参考 老罗-罗升阳的《Android日志系统驱动程序Logger源代码分析》

    https://blog.csdn.net/luoshengyang/article/details/6595744

        本节主要来分析logd、logcat的相关实现原理。

    2.核心源码

    /frameworks/base/core/java/android/util/Log.java
    /frameworks/base/core/java/android/util/SLog.java
    /frameworks/base/core/java/android/util/EventLog.java
    /frameworks/base/core/jni/android_util_Log.cpp
    /system/core/logd/main.cpp
    /system/core/logd/LogReader.cpp
    /system/core/logd/LogWriter.java
    /system/core/logcat/logcat.cpp
    /system/core/liblog/logd_writer.cpp
    /system/core/liblog/logd_reader.cpp

    3.logcat相关指令说明

        手机连上电脑,安装adb驱动后,打开开发者模式,选择"USB调试",即可执行adb 命令

     

    3.1 命令行语法

        要通过 adb shell 运行 Logcat,一般用法如下:

        [adb] logcat [<option>] ... [<filter-spec>] ...

     

    3.2 指令说明

        可以通过 "adb logcat --help" 来看logcat支持的指令。

        详细信息参考  《Logcat 命令行工具》

    https://developer.android.google.cn/studio/command-line/logcat

    3.3 日志过滤输出

        Android日志分为如下7个等级

    • V:详细(最低优先级)--(Verbose:2)

    • D:调试 --(Debug:3)

    • I :信息 -- (Info:4)

    • W:警告 --(Warning:5)

    • E:错误 --(Error:6)

    • F:严重错误 --(Fatal:7)

    • S:静默(最高优先级,绝不会输出任何内容)--(Silent)

        我们在调试日志时,可以根据不同的等级来控制日志的输出

        下面这是一条正常输出的Android日志

        日志:02-05 12:44:15.357 17533 17545 D ActivityThread: caller system = false

        日志格式:<日期> <时间> <PID>  <TID>  <日志等级> <日志标签TAG>  <日志内容>

        

    我们可以通过过滤器只输出相应等级以下的日志:

    1)例如:adb logcat  *:I

        指令含义:输出日志等级为Info以上的日志,即只输出Info、Error、Fatal、Silent的日志, Debug、Verbose的日志不会输出

     

    2)例如:adb logcat ActivityManager:E ActivityThread:I *:S

        指令含义:该表达式会抑制除标记为“ActivityManager”、优先级不低于“Error”的日志消息,以及标记为“ActivityThread”、优先级不低于“Info”的日志消息以外的所有其他日志消息。

     

    3)例如:adb logcat ActivityThread:E *:S

        指令含义:只输出标签为ActivityThread 且日志等级大于等于Error的日志,即只输出ActivityThread的 Error、Fatal的日志

     

    3.4 日志输出格式

        除标记和优先级外,日志消息还包含许多元数据字段。您可以修改消息的输出格式,以便它们显示特定的元数据字段。为此,您可以使用 -v 选项,并指定下列某一受支持的输出格式。

    • brief:显示优先级、标记以及发出消息的进程的 PID。

    • long:显示所有元数据字段,并使用空白行分隔消息。

    • process:仅显示 PID。

    • raw:显示不包含其他元数据字段的原始日志消息。

    • tag:仅显示优先级和标记。

    • thread::旧版格式,显示优先级、PID 以及发出消息的线程的 TID。

    • threadtime(默认值):显示日期、调用时间、优先级、标记、PID 以及发出消息的线程的 TID。

    • time:显示日期、调用时间、优先级、标记以及发出消息的进程的 PID。

    指令: [adb] logcat [-v <format>]

    例如:adb logcat -v threadtime

    注意:-v每次只能使用一种格式,默认情况下的threadtime格式即能满足我们现在的需求

     

    3.5 日志缓冲区

        Android 日志记录系统为日志消息保留了多个环形缓冲区,而且并非所有的日志消息都会发送到默认的环形缓冲区。要查看其他日志消息,您可以使用 -b 选项运行 logcat 命令,以请求查看备用的环形缓冲区。您可以查看下列任意备用缓冲区:

    • radio:查看包含无线装置/电话相关消息的缓冲区。

    • events:查看已经过解译的二进制系统事件缓冲区消息。

    • main:查看主日志缓冲区(默认),不包含系统和崩溃日志消息。

    • system:查看系统日志缓冲区(默认)。

    • crash:查看崩溃日志缓冲区(默认)。

    • all:查看所有缓冲区。

    • default:报告 main、system 和 crash 缓冲区。

    用法1:adb logcat -b main

    说明1:上述指令只输出main缓冲区的日志。

    用法2:adb logcat -b main,radio,system

    说明2:上述指令输出 main、radio、system三个缓冲区的日志

     

    4. 日志系统相关属性说明

    属性

    说明

    log.tag.*

    setprop log.tag.MyApp D

    用来设置应用日志TAG的等级,上面是输出MyApp的Debug日志,主要控制的是isLoggable(MyApp,Debug) 这种方式控制的日志

    手动设置后,重启失效

    ro.logd.auditd

    启动selinux审核守护进程

    ro.logd.auditd.dmesg

    selinux审核信息发送到dmesg log

    ro.logd.kernel

    cat “/proc/kmsg” 节点,用来读取kernel日志

    ro.logd.size

    所有日志缓存区大小的默认大小,默认为256K,可实时修改,重启失效

    ro.logd.timestamp

    修改日志时间戳,可以实时修改,重启失效

    ro.logd.filter

    日志黑白名单是否生效,disable为失效,enable为生效

    logd.statistics

    使能logcat -S statistics,在输出中包含统计信息,以帮助您识别和定位日志垃圾信息发送者

    persist.logd.timestamp

    修改日志时间戳,只能编译版本的时候修改,或者手机root后修改,重启继续生效

    persist.logd.size

    所有日志缓存区大小的默认大小,默认为256K只能编译版本的时候修改,或者手机root后修改,重启继续生效

    persist.logd.size.main

    main日志缓冲区大小,默认为256K

    persist.logd.size.system

    system日志缓冲区大小,默认为256K

    persist.logd.filter

    日志黑白名单是否生效,disable为失效,enable为生效,

    通过adb logcat -p 来读取黑白名单;

    通过logcat -P '<white_and_blacklist>' 来设置黑白名单,通过PID\UID来进行控制

    persist.log.tag

    setprop persist.log.tag Debug

    控制Debug以上等级的日志输出,只有在版本预制,或者root后,设置生效,重启也生效

    ro.logd.kernel

    setprop ro.logd.kernel true

    控制内核日志输出到logd的buffer中,通过lgocat抓取

    ro.logd.auditd

    setprop ro.logd.auditd true

    控制selinux日志输出到logd的buffer中,通过lgocat抓取

     

    我们在日常调试或者CTS测试时,会遇到日志丢失或者不全的情况,主要原因是日志量很大,但是日志缓冲区很小,此时只要把日志的缓冲区调大即可。

    方法1: setprop ro.logd.size 5120     即把日志缓冲区都调整为5M

    方法2:开发者模式->日志记录缓冲区大小-> 选择相应的缓冲区大小,可以选择64K -16M等5个大小

     

    5. 日志分类

    Android10.0上日志分为8类:

    ID

    对应值

    说明

    LOG_ID_MAIN

     

    0

    main日志缓冲区,这是应用程序唯一可用的日志缓冲区,在应用框架层提供了android.util.Log接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOGV、LOGD、LOGI、LOGW、LOGE用来写入main类型的日志。

    LOG_ID_RADIO

    1

    查看包含无线装置/电话相关消息的日志,可以调用android.telephony.Rlog进行打印

    LOG_ID_EVENTS

    2

    类型为events的日志是用来诊断系统问题的,在应用框架层提供了android.util.EventLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏LOG_EVENT_INT、LOG_EVENT_LONG、LOG_STRING用来写入event类型的日志。

    LOG_ID_SYSTEM

    3

    类型为system的日志是系统级别的,在应用框架层提供了android.util.SLog接口通过liblog库来往Logger日志驱动程序中写入日志,在运行时库提供了宏SLOGV、SLOGD、SLOGI、SLOGW、SLOGE用来写入system类型的日志。

    LOG_ID_CRASH

    4

    应用或者进程crash日志缓冲区

    LOG_ID_STATS

    5

    统计日志缓冲区

    LOG_ID_SECURITY

    6

    安全日志缓冲区

    LOG_ID_KERNEL

    7

    kernel日志缓冲区

     

    我们常用的日志缓冲区为:main、radio、system、events、crash

    另外内核的日志,主要是输出到/proc/kmsg, 通过 cat /proc/kmsg 获取内核日志。

     

    下一节我们一起来看看<Android 日志系统的架构分析>

    微信公众号:IngresGe

     

     

    展开全文
  • ELK日志系统浅析与部署

    万次阅读 多人点赞 2018-06-22 03:58:12
    一、ELK应用场景在复杂的企业应用服务群中,记录日志方式多种多样,并且不易归档以及提供日志监控的机制。无论是开发人员还是运维人员都无法准确的定位服务、服务器上面出现的种种问题,也没有高效搜索日志内容从而...
  • java日志系统框架整理(转载)

    万次阅读 2018-02-06 11:45:38
    首先,在日志系统的森林里面理理头绪,修炼内功。参考文章如下: 1.https://www.cnblogs.com/gavanwanggw/p/7305218.html 2.https://www.cnblogs.com/gavanwanggw/p/7305218.html Java日志系统确实比较丰富,...
  • Unity自定义日志系统

    千次阅读 2019-05-28 18:14:26
    Unity的系统日志算是很好用,但当程序很大时,就会比较乱,所以在项目中我们往往要对日志系统进行重新封装使用。 一、日志系统封装 如下代码,我们可以通过m_Log来控制是否打印日志,或对输出的日志加入时间等修改...
  • 本文将从海量日志系统在优化、部署、监控方向如何更适应业务的需求入手,重点从多种日志系统的架构设计对比;后续调优过程:横向扩展与纵向扩展,分集群,数据分治,重写数据链路等实际现象与问题展开。日志系统架构...
  • Linux之日志系统

    千次阅读 2016-12-09 12:08:36
    我们可以使用日志系统所记录的信息为系统进行排错,优化系统的性能,或者根据这些信息调整系统的行为。收集你想要的数据,分析出有价值的信息,可以提高系统、产品的安全性,可以帮助开发完善代码,优化产品。日志会...
  • 全栈工程师开发手册 (作者:栾鹏) python教程全解 ...django使用python内建的logging模块去建造自己的系统日志的,如果你想详细了解这个模块的话,请自己去看python的说明文档,这里仅仅介绍d...
  • 深入理解数据库日志系统原理

    千次阅读 2016-02-29 21:20:30
     事务管理系统需要做两件事,1)让日志系统产生日志,2)保证多个事务并发执行,满足ACID特性。  事务系统工作模型,见图1。    如图,事务管理管理器控制查询处理器的执行、控制日志系统以及缓冲区。日志在...
  • C++实现log日志系统

    万次阅读 2018-04-19 14:33:10
    1.log日志的作用在软件开发周期中,不管是前台还是后台,系统一般会采用一个持久化的日志系统来记录运行情况。在代码中嵌入log代码信息,主要记录下列信息:(1)记录系统运行异常信息。(2)记录系统运行状态信息。...
  • Loki日志系统详解1——背景

    万次阅读 2019-09-06 10:56:05
    Loki日志系统详解1——背景 Loki日志系统详解1——背景 最近,在对公司容器云的日志方案进行设计的时候,发现主流的ELK或者EFK比较重,再加上现阶段对于ES复杂的搜索功能很多都用不上最终选择了Grafana开源的Loki...
  • 在QT中使用日志系统

    千次阅读 2019-03-27 09:20:31
    当写好的软件发布出去后,用户遇到死机或一些其他的bug,我们该怎么追踪这些问题呢,这时候日志系统很好的帮助了我们。最近也是参照网络大牛的博客代码实现了log。下面看看代码吧。 void outputMessage(QtMsgType...
  • 数据库日志系统原理详解

    万次阅读 2016-04-14 13:17:59
     日志系统原理 作者:杨万富 一:事务系统1.事务的工作模型 事务必须满足原子性,所封装的操作或者全做或者全不做。事务管理系统需要做两件事,1)让日志系统产生日志,2)保证多个事务并发执行,满足ACID特性。...
  • 大型开源日志系统比较

    千次阅读 2016-07-01 16:35:34
    许多公司的平台每天会产生大量的日志(一般为流式数据,如,搜索引擎的pv,查询等),处理这些日志需要特定的日志系统,一般而言,这些系统需要具有以下特征: (1) 构建应用系统和分析系统的桥梁,并将它们之间...
  • Loki日志系统详解2——架构

    千次阅读 2019-09-06 11:08:18
    Loki日志系统详解2——架构 整体架构 Loki的架构如下: 不难看出,Loki的架构非常简单,使用了和prometheus一样的标签来作为索引,也就是说,你通过这些标签既可以查询日志的内容也可以查询到监控的数据,不但减少...
  • 日志系统之定时任务执行引擎

    千次阅读 2016-04-23 22:07:55
    概述最近这段时间在强化日志系统自身的稳定性和可靠性,一个稳定可靠的系统离不开监控,我们这里谈及的监控除了服务是否存活还有这些组件的核心metrics采集与抓取,为此我们将这些任务做成了定时任务来执行。...
  • 最近我在日志收集的功能中加入了对docker容器日志的支持。这篇文章简单谈谈策略选择和处理方式。
  • 使用ElasticSearch搭建日志系统

    千次阅读 2018-02-23 13:45:03
    如果:• 你有很多台机器• 你有各种各样的Log只要满足这两个条件其中之一,那么一套日志系统是很有必要的。优秀的日志系统可以让你及时发现问题,轻松追查故障原因,进而提高生产力。本文简单介绍一下怎么用...
  • 每个软件都有自己的日志系统,每种语言都有自己的日志框架/模块,随着互联网和大数据的蓬勃发展,分布式的日志系统,以及日志分析系统也应用的越来越广泛,越来越成熟。这里讨论的日志设计,主要关注日志的内容,而...
  • C#日志系统之实时打印实现

    千次阅读 2018-07-17 13:35:26
    这个日志系统不算大,但也有一些含金量,初学者可以通过这个项目快速的掌握C#的一些用法,以及winform编程里面用到的思想。实现两大类功能,一类是实时日志,另一类是历史日志,下面是实时日志的界面。    ...
  • 打造 NestJS 日志系统

    千次阅读 2020-03-11 18:12:26
    Nest系统日志打印 配置入口,这里传入一个自定义日志类。但实际上实现了LoggerService接口的类都可以。 其中BasicLogger 是自定义封装命名的类。 const app = await NestFactory.create<...
  • 日志系统ELK使用详解(一)--如何使用

    万次阅读 2017-05-14 11:34:49
    概述当我们管理和使用的后端服务程序突破单台场景,进入到集群部署场景时,日志文件就会散落在多台后端服务器上。这时候要查看、统计日志信息就需要到各个服务器上去取和查看,...在业内常见的部署组合就是ELK系统了。
  • spring整合logback日志系统框架

    万次阅读 2017-09-05 11:05:13
    记录,生成应用的异常信息是维护应用的重要手段,项目中常用的spring框架整合日志,最流行的就是logback,我们公司目前用的也是这个。和spring整合比较简单。 log4j与logback简要比较 本文意在阐述用logback替代log...
  • 多缓冲提高日志系统性能

    千次阅读 热门讨论 2015-08-11 07:18:50
    前言:无论什么项目肯定都少不了日志系统,所以一个高性能的日志系统是不可避免的。 本文介绍的是自己用c++11实现的一个简单的多缓冲区日志系统,比较水,仅供参考^_^ 主题: 日志系统及重要性 单缓冲日志系统模型...
  • 日志系统框架的设计与实现

    千次阅读 2014-08-02 12:36:11
    日志系统作为一种应用程序服务,对于跟踪调试、程序状态记录、崩溃数据恢复都有着重要的作用,我们可以把Java日志系统看作是必不可少的跟踪调试工具。  1.简介  日志系统是一种不可或缺的跟踪调试工具,特别...
  • 从ELK到EFK,日志系统的高级玩法儿

    万次阅读 2017-10-19 13:58:41
    为了提供分布式的实时日志搜集和分析的监控系统,我们采用了业界通用的日志数据管理解决方案,主要包括Elasticsearch、Logstash和Kibana三个系统

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,274,536
精华内容 509,814
关键字:

日志系统