针对中小型项目,介绍一下简单廉价的日志处理方式。
日志的处理方式多种多样,从裸日志文件到使用消息队列,再到日志分析,各有所长。
比较流行的开源产品有 ELK,Loki。除此之外,个大云厂商都有相应的日志处理服务。
棘手的问题
在做日志处理的时候,有几个棘手的问题。
- 日志格式
 - 日志推送
 - 日志检索
 - 费用
 
日志格式
为了能让之日检索更为方便,我们不得不去固定日志格式,因为日志处理系统还无法如此智能到,把任意格式的日志文件,格式化成检索模式。
由此带来的问题就是,开发者需要格外注意日志格式,何时写日志,写什么信息等等。不过,业务压力巨大的情况下,很难精益求精。
日志推送
简简单单推送日志很简单,像 filebeat, promtail 这些小程序,都可以把本地日志文件推送到服务端进行分析存储。这里的最麻烦的问题是,推送到日志存储服务之前,
我们通常会对裸日志进行一些简单处理。举例来说,在经典 filebeat -> logstash -> elasticsearch 模式中,logstash 就是扮演日志【分拣员】的角色。用过 logstash 的人都应该有体验,
这里的语法及其繁琐,而且动不动就会出现日志格式不匹配,而导致日志被丢掉的情况。
日志检索
像 Elasticsearch+Kibana, Splunk 都有着出色的检索功能,不过并不像搜索引擎一样,随意填写关键字,就可以检索出来,这里也有它自己的语法。而且随着这些产品的迭代,使用门槛也越来越高。
Demo 里的图表很绚丽,不过要想做出这种绚丽的图表,需要做的事情非常繁琐,对于刚上手的人来说,几天的时间,很难搞清楚。
费用
费用也是一个不能忽视的因素。随着规模越来越大,日志存储服务的费用也会随之升高。像专业版的 ELK,商业版的日志处理引擎,动不动就要上千,上万。日志是解决线上问题的必要因素,不能丢弃,所以这部分开销,对于中小规模团队,企业来说,是很大的负担。
简单日志处理需要什么?
我们暂时不讨论大规模的业务日志应该如何处理。在中小规模的业务中,尤其是小规模业务,我们需要的就是日志存储 + 检索(哪怕是 grep)。
高级的检索,绘制图表功能,其实并不需要。
简单廉价解决方案

这里我们介绍的是 rk-boot/v2 + Loki + Grafana + 对象存储的解决方案。
避开棘手的问题
在这个方案中,我们没有使用到 filebeat, promtail 这种日志采集器,也没有使用日志推送进程。因为是小规模场景,把【棘手的问题】忽略掉,是一个不错的选择。
我们使用 rk-boot/v2 直接往 loki 中推送日志,即避免了繁琐的正则表达式,也不用考虑日志采集器不工作的问题,同时,也不用考虑日志格式的问题。
便宜
- 代码成本:我们使用的都是开源程序
 - 存储成本:对象存储的单价非常便宜,以腾讯云为例,0.118元/GB/月,如果再加上免费额度,几乎花不了什么钱。至于流量费用,入流量是免费的,出流量虽然贵一些,不过,日志检索不是每时每刻都在做,在承受范围之内。
 - 运维成本:少了采集器,推送服务,以及日志格式处理,运维成本大大降低。
 
Demo
1.使用 Docker 启动 Loki
我们将会使用 Docker 来启动 Loki,并且在 Loki 配置文件中,指定写入到腾讯云对象存储,当然,也可以写入到任何与 AWS S3 兼容的对象存储中。
我们首先到腾讯云创建一个账号,然后开一个存储桶,当然,记得往里存个1块钱,否则无法开通服务。
- loki.yaml
 
创建一个 loki.yaml 文件,Docker 启动 Loki 的时候,会把这个文件挂载到 Docker 镜像中。
# 除了 aws 相关参数,剩下的可以保留成如下的默认值
auth_enabled: false
server:
  http_listen_port: 3100
  
ingester:
  wal:
    dir: /loki/wal
  lifecycler:
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
schema_config:
  configs:
    - from: 2020-10-24
      store: boltdb-shipper
      object_store: aws
      schema: v11
      index:
        prefix: loki_index_
        period: 24h
storage_config:
  aws:
    bucketnames: loki-logs-1310384686                                # 请在腾讯云创建一个对象存储存储桶,并把存储桶名称写到这里
    endpoint: cos.ap-beijing.myqcloud.com                            # 腾讯云的对象存储域名后缀
    access_key_id: <Your access key id from TencentCloud>            # 腾讯云 AK
    secret_access_key: <Your secret access key from TencentCloud>    # 腾讯云 SK
    region: ap-beijing                                               # 对象存储存储桶地域
  boltdb_shipper:
    active_index_directory: /loki/index
    shared_store: s3
    cache_location: /loki/boltdb-cache
compactor:
  working_directory: /loki/boltdb-shipper-compactor
  shared_store: aws
复制代码
- 启动 loki
 
-v 后面给出自己的当前路径。
$ docker run -v /Users/dongxuny/workspace/rk/rk-demo/gin/basic/loki.yaml:/etc/loki/local-config.yaml -p 3100:3100 grafana/loki
复制代码
2.使用 Docker 启动 grafana 并配置 Loki
初始化账号: admin
初始化密码:admin
$ docker run -p 3000:3000 grafana/grafana
复制代码

- 选择 Loki 为数据源
 

- 配置 Loki 地址
 

3.下载 rk-boot/v2
rk-boot/v2 是可以通过 YAML 文件启动 Golang 流行框架的依赖库,里面包含了很多实用中间件。
为了模拟微服务,我们同时还下载 rk-gin/v2 来启动 gin-gonic 服务。
$ go get github.com/rookie-ninja/rk-boot/v2
$ go get github.com/rookie-ninja/rk-gin/v2
复制代码
4.配置 boot.yaml
创建一个 boot.yaml 文件。boot.yaml 文件告诉 rk-boot/v2 启动哪些 Gin 配套的服务。
---
logger:
  - name: logger
    loki:
      enabled: true
      addr: localhost:3100        # 往 Loki 里推送日志
event:
  - name: event
    loki:
      enabled: true
      addr: localhost:3100        # 往 Loki 里推送 Event 类型日志
gin:
  - name: greeter
    port: 8080
    enabled: true
    loggerEntry: logger           # 告诉 Gin 使用 logger 作为日志实例
    eventEntry: event             # 告诉 Gin 使用 event 作为 Event 日志实例
    middleware:
      logging:
        enabled: true             # 启动日志中间件,API 会自动记录日志,并发送到 Loki 中
复制代码
5.写个 API
// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main
import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/rookie-ninja/rk-boot/v2"
	"github.com/rookie-ninja/rk-gin/v2/boot"
	"github.com/rookie-ninja/rk-gin/v2/middleware/context"
	"net/http"
)
func main() {
	// Create a new boot instance.
	boot := rkboot.NewBoot()
	// Register handler
	ginEntry := rkgin.GetGinEntry("greeter")
	ginEntry.Router.GET("/v1/greeter", Greeter)
	// Bootstrap
	boot.Bootstrap(context.Background())
	// Get logger and event instance with bellow functions
	//logger := rkentry.GlobalAppCtx.GetLoggerEntry("logger")
	//event := rkentry.GlobalAppCtx.GetEventEntry("event")
	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}
func Greeter(ctx *gin.Context) {
	rkginctx.GetLogger(ctx).Info("Can you see me from Grafana Loki dashboard?")
	ctx.JSON(http.StatusOK, &GreeterResponse{
		Message: fmt.Sprintf("Hello %s!", ctx.Query("name")),
	})
}
type GreeterResponse struct {
	Message string
}
复制代码
6.启动 main.go & 发送请求
$ go run main.go
$ curl localhost:8080/v1/greeter
复制代码
7.日志检索
当开启日志中间件,rk-boot/v2 默认会对每个 API 记录 Event 类型的日志。
- API 日志
 


- 应用日志
 
可以通过 rkginctx.GetLogger(ctx).Info(“XXX”) 方式获取当前请求相关的 logger 实例,当开启 meta 中间件的时候,这个 logger 实例会默认打印 RequestID。


- 搜索
 
Loki 有一套检索语法 ,还比较好理解。

8.验证对象存储桶
登陆腾讯云,验证数据是否正常写入到对象存储。

9.后期运维 & 线上配置 Loki
这里我们只是给了一个单机版的例子,在实际项目当中,我们建议使用 HELM 往 K8S 容器中部署 Loki。
至于费用方面,各大云长上提供了【弹性 K8S 集群】,价格也很便宜,以腾讯云为例,一个 1 CPU, 1 GB 内存的弹性 POD,每个月的大概需要 ¥45,再加上对象存储相关费用,负载均衡,¥100 以内是可以搞定的。
对于中小规模项目,日志方面的开销,完全可以接受。
10.大规模项目
在上面的方案中,我们没有使用任何数据库相关的产品来处理检索引擎,大规模项目,日志庞大的话,LOKI 显然会出现性能瓶颈。这时候,可以考虑切换到商业版日志处理产品。毕竟业务大了,开销也可以上涨。






















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)