本节重点介绍 :

  • 新建项目 log2metrics
  • 编写配置文件yaml
  • main 解析配置,校验正则,设置log
  • 根据配置文件设置metrics

新建项目 log2metrics

go mod init

go mod init log2metrics

编写配置文件yaml

http_addr: 0.0.0.0:8087
log_level: INFO

log_strategy:
  - metric_name: log_containerd_total
    metric_help: /var/log/messages 中的 containerd日志 total
    file_path: /var/log/messages
    pattern:  ".*containerd.*"
    func: cnt
    tags:
      level: ".*level=(.*?) .*"
  - metric_name: ngx_acc_code
    metric_help: nginx code avg
    file_path: /var/log/nginx/access.log
    pattern:  '.*\[code=(.*?)\].*'
    func: avg

log_strategy 字段解析

  • metric_name :指定暴露的metrics名称 如 ngx_access_cnt
  • metric_help : 暴露指标的metrics帮助信息,支持中文
  • file_path : 指定日志路径
  • pattern:提供日志匹配正则 ,如过滤包含 containerd的日志
  • func :计算方法
  • cnt 对符合规则的日志进行计数 ,就是日志的总数counter
  • max 对符合规则的日志抓取出的数字算最大值 ,如code=404 和code=500 max结果就是 500
  • min 对符合规则的日志抓取出的数字算最小值
  • sum 对符合规则的日志抓取出的数字算和
  • avg 对符合规则的日志抓取出的数字算平均值
  • tags:标签的正则,
  • key=正则
  • key最后用来设置metrics的标签
  • value正则匹配的结果是标签的值

代码中解析配置文件

日志采集策略文件

  • 位置strategy/log.go
  • 代码
package strategy

import "regexp"

type Strategy struct {
	ID         int64  `json:"id" yaml:"-"`
	MetricName string `json:"metric_name" yaml:"metric_name" ` //监控策略名
	MetricHelp string `json:"metric_help" yaml:"metric_help" ` //metric help信息

	FilePath   string                    `json:"file_path" yaml:"file_path"` //文件路径
	Pattern    string                    `json:"pattern" yaml:"pattern"`     //正则表达式
	Tags       map[string]string         `json:"tags" yaml:"tags"`           // 配置的标签正则
	Func       string                    `json:"func" yaml:"func" `          //计算方式(max/min/avg/cnt)
	Creator    string                    `json:"creator"`
	PatternReg *regexp.Regexp            `json:"-"` // 正则表达式配置解析后的
	TagRegs    map[string]*regexp.Regexp `json:"-"` // 配置的标签正则解析后的
}

解析配置的方法

  • 位置 config/config.go
package config

import (
	"fmt"
	"github.com/toolkits/pkg/logger"
	"io/ioutil"
	"log2metrics/strategy"
	"regexp"

	"gopkg.in/yaml.v2"
)

type Config struct {
	LogStrategies []*strategy.Strategy `yaml:"log_strategy"`
	LogLevel      string               `yaml:"log_level"`
	HttpAddr      string               `yaml:"http_addr"`
}

func Load(s string) (*Config, error) {
	cfg := &Config{}

	err := yaml.Unmarshal([]byte(s), cfg)

	if err != nil {
		return nil, err
	}
	cfg.LogStrategies = updateRegs(cfg)
	return cfg, nil
}
func updateRegs(cfg *Config) []*strategy.Strategy {
	res := []*strategy.Strategy{}
	for _, st := range cfg.LogStrategies {
		st := st
		//更新pattern
		if len(st.Pattern) != 0 {
			reg, err := regexp.Compile(st.Pattern)
			if err != nil {
				logger.Errorf("compile pattern regexp failed:[sid:%d][pat:%s][err:%v]", st.ID, st.Pattern, err)
				continue
			}
			st.PatternReg = reg
		}
		st.TagRegs = map[string]*regexp.Regexp{}
		//更新tags
		for tagk, tagv := range st.Tags {
			reg, err := regexp.Compile(tagv)
			if err != nil {
				logger.Errorf("compile tag failed:[sid:%d][pat:%s][err:%v]", st.ID, tagv, err)
				continue
			}
			st.TagRegs[tagk] = reg
		}
		res = append(res, st)

	}
	return res
}

func LoadFile(filename string) (*Config, error) {
	content, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	cfg, err := Load(string(content))
	if err != nil {
		fmt.Printf("[parsing YAML file errr...][error:%v]", err)
		return nil, err
	}
	return cfg, nil
}
updateRegs校验用户配置的正则
  • 使用regexp.Compile解析 st.Pattern
  • 如果报错了说明用户配置的正则不对,那么就忽略这个配置
  • 对于标签的正则st.TagRegs的处理方式是
  • 如果一个正则配置错误就忽略这个标签

main 解析配置,设置log

解析命令行

package main

import (
	"context"
	"github.com/oklog/run"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/promlog"
	promlogflag "github.com/prometheus/common/promlog/flag"
	"github.com/prometheus/common/version"
	"github.com/toolkits/pkg/logger"
	"gopkg.in/alecthomas/kingpin.v2"
	"log2metrics/common"
	"log2metrics/config"
	"log2metrics/consumer"
	"log2metrics/counter"
	"log2metrics/logjob"
	"log2metrics/metrics"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
)

func main() {

	var (
		// 命令行参数
		app = kingpin.New(filepath.Base(os.Args[0]), "The log2metrics")
		// 指定配置文件
		configFile = app.Flag("config.file", "log2metrics configuration file path.").Default("log2metrics.yml").String()
	)
	promlogConfig := promlog.Config{}
	//
	app.Version(version.Print("log2metrics"))
	app.HelpFlag.Short('h')
	promlogflag.AddFlags(app, &promlogConfig)
	kingpin.MustParse(app.Parse(os.Args[1:]))

解析配置文件和设置log

// 解析yaml配置文件
	sConfig, err := config.LoadFile(*configFile)
	if err != nil {
		logger.Infof("config.LoadFile Error,Exiting ...error:%v", err)
		return
	}

	// 设置日志级别
	logger.SetSeverity(sConfig.LogLevel)

根据配置文件设置metrics

  • 位置 metrics/metrics.go
package metrics

import (
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"log2metrics/strategy"
	"net/http"
)

func CreateMetrics(ss []*strategy.Strategy) map[string]*prometheus.GaugeVec {
	mmap := make(map[string]*prometheus.GaugeVec)
	for _, s := range ss {
		labels := []string{}
		for k := range s.Tags {
			labels = append(labels, k)
		}
		m := prometheus.NewGaugeVec(prometheus.GaugeOpts{
			Name: s.MetricName,
			Help: s.MetricHelp,
		}, labels)
		mmap[s.MetricName] = m

	}
	return mmap

}

解读

  • 遍历配置文件解析完之后的策略数组
  • 初始化一个gauge类型的metrics
  • 名字为用户配置的 MetricName
  • Help为用户配置的 MetricHelp
  • labels为用户配置的 tags的key
  • 以metrics 的name为key,value是这个metrics 创建一个map

main.go中创建这个metrics的map

  • 遍历metrics map,注册metrics
// 创建metrics
	metricsMap := metrics.CreateMetrics(sConfig.LogStrategies)
	// 注册metrics
	for _, m := range metricsMap {
		prometheus.MustRegister(m)
	}

本节重点总结 :

  • 新建项目 log2metrics
  • 编写配置文件yaml
  • main 解析配置,设置log
  • 根据配置文件设置metrics