在java微服务项目中,我们对于线上的项目都要求做日志采集,这样子便于即使的发现上线的问题。
在常用的日志采集方案主要是ELK,但是ELK的整套系统其实对服务器的配置等要求还是比较高的。像我们这种做某个项目的时候,服务器数量,预算等都卡的非常严的项目里面,ELK的方案对于我们来说就非常大了。但是日志采集这个东西他又不可或缺。所以对于我们现在内部来说,采用的方案主要是Loki+Grafana的方式。这是一个非常轻量级的日志采集方案。本文我们就来介绍下Loki+Grafana的实施方案。
一、安装docker+docker-compose
一般来说我们使用Loki+Grafana的话都是使用docker的方式部署即可,这样子占用的资源比较少,像做ToG项目的话,内存一般不超过2G。所以使用起来比较轻量级,同时也更简单。
这里docker的安装教程可参考:《Docker最新版安装教程》。
这里docker-compose的安装教程可参考:《Docker-compose安装教程》
二、编写docker-compose.yml
这里我们主要是使用docker+docker-compose来运行Loki+Grafana,所以的话我们直接编写一个docker-compose文件,方便后续启动部署。示例文件内容如下;
version: "3" networks: loki: services: loki: image: grafana/loki:latest ports: - "3100:3100" command: -config.file=/etc/loki/local-config.yaml networks: - loki grafana: environment: - GF_PATHS_PROVISIONING=/etc/grafana/provisioning - GF_AUTH_ANONYMOUS_ENABLED=true - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin entrypoint: - sh - -euc - | mkdir -p /etc/grafana/provisioning/datasources cat <<EOF > /etc/grafana/provisioning/datasources/ds.yaml apiVersion: 1 datasources: - name: Loki type: loki access: proxy orgId: 1 url: http://loki:3100 basicAuth: false isDefault: true version: 1 editable: false EOF /run.sh image: grafana/grafana:latest ports: - "3000:3000" networks: - loki
创建完成之后,我们使用docker-compose把docker容器启动起来:
docker-compose up -d
启动完成之后,我们就可以看到这里的loki和grafana容器都启动起来了。
这里我们可以可视化的访问一下grafana
默认的用户名和密码是:admin和admin
三、添加Loki agent
这里既然我们主打轻量级,所以我们肯定不会在服务器端部署采集的agent,那么我们如何采集呢?就是常用的做法,也就是在java项目里面使用log的方式想loki输出日志。这里我们以springboot为例来演示一下。
1)准备一个springboot项目
这里我们以之前的mybatis的demo来演示一下:
2)添加loki依赖
接下来在maven的pom里面添加loki的依赖
<dependency> <groupId>com.github.loki4j</groupId> <artifactId>loki-logback-appender-jdk8</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency>
3)添加logback配置文件
这里的话在logback里面配置向loki输出信息,具体的logback配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <springProperty name="appName" scope="context" source="spring.application.name" /> <springProperty name="lokiUrl" scope="context" source="loki.url" /> <springProperty name="serverPort" scope="context" source="server.port" defaultValue="8080" /> <springProperty name="log_home" scope="context" source="log.home" /> <springProperty name="log_file_name" scope="context" source="spring.application.name" /> <property name="APP_NAME" value="${appName}" /> <property name="LOKI_URL" value="${lokiUrl}" /> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <property name="LOG_HOME" value="logs" /> <!--日志文件的名字--> <property name="LOG_FILE_NAME" value="${log_file_name}" /> <conversionRule conversionWord="server_ip" converterClass="com.mybatis.demo.utils.LocalIpAddress" /> <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender"> <http class="com.github.loki4j.logback.ApacheHttpSender"> <url>${LOKI_URL}/loki/api/v1/push</url> </http> <format> <label> <pattern>app=${APP_NAME},instance=${%magenta(%server_ip)}:${serverPort}, level=%level</pattern> </label> <message> <pattern>l=%level i=${%magenta(%server_ip)}:${serverPort} c=%logger{20} t=%thread | %msg %ex</pattern> </message> <sortByTime>true</sortByTime> </format> </appender> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度,%msg:日志消息,%n是换行符--> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </layout> </appender> <!--INFO级别消息日志(文件日志, 按照每天生成日志文件)--> <appender name="INFO_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${LOG_FILE_NAME}.log</file> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!--日志文件输出的文件名--> <fileNamePattern> ${LOG_HOME}/${LOG_FILE_NAME}_info_%d{yyyy-MM-dd}_%i.log</fileNamePattern> <maxFileSize>100MB</maxFileSize> <!--日志文件保留天数--> <maxHistory>90</maxHistory> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> </appender> <!--ERROR级别消息日志--> <appender name="ERROR_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${LOG_FILE_NAME}_error.log</file> <encoder> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern> ${LOG_HOME}/${LOG_FILE_NAME}_error_%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>90</maxHistory> <totalSizeCap>1GB</totalSizeCap> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 --> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 日志输出级别 --> <root level="INFO"> <appender-ref ref="LOKI" /> <appender-ref ref="STDOUT" /> <appender-ref ref="INFO_LOG_FILE" /> <appender-ref ref="ERROR_LOG_FILE" /> </root> </configuration>
这里的logback有占位符,所以我们需要把这里的占位符配置信息配置到配置文件里面去,接下来我们去application.properties文件中进行配置:
loki.url=http://192.168.31.20:3100 spring.application.name=mybatisdemo server.port=8080
同时这里的话我们instance获取了本地的ip,所以这里我们也需要编写一个获取ip的类,示例图如下:
这里的配置对应的logback里面的:
四、添加打印log
接下来我们只需要在代码里面使用log打印日志即可,例如我们这里的演示log:
请求一下,可以看到控制台输出了日志信息:
五、验证loki+grafana
接下来我们验证一下,日志是否输出到了loki中,这里使用grafana进行展示,首先登录grafana,然后创建一个数据源,选择loki即可:
这里我们只需要填写loki的url连接即可,由于docker-compose里面配置的单独的网络,所以这里的host我们使用loki的docker容器名称。创建完成之后就可以看到loki数据源了。
然后我们创建一个dashboard,选择Add a new panel即可:
进来后可以选择filter查看,选择app=xxx即可,示例图如下:
选择完毕之后,点击这里的Run queryes,然后再点击Open visualization suggestions即可:
就可以看到所有的日志了:
然后我们保存这个dashboard即可:
最后这个看起来不太直观,我们还可以用kinaba看流水的方式查看日志,点击这个Panel Title:
选择这里的View就可以了,进去后如下图:
这里看起来也不直观,我们继续点击这个Panel Ttitle,然后点击Explore:
点击之后就可以进行筛选了:
以上就是使用Loki+grafana做轻量级日志采集的方案,是不是很简单。
备注:
1、这里的loki没有做持久化,所以在真实部署的时候需要配置持久化。 2、logback里面的配置项比较多,有很多占位符,需要大家多看看。 3、如果loki服务没启动的话,日志会报错,但是不会影响程序的正常运行。
最后按照惯例,我们附上springboot项目的代码,登录后即可查看。
还没有评论,来说两句吧...