在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项目的代码,登录后即可查看。




















还没有评论,来说两句吧...