基于Prometheus的client_golang库实现应用的自定义可观测监控

文章目录

    • 1. 安装client_golang库
    • 2. 编写可观测监控代码
    • 3. 运行效果
    • 4. jar、graalvm、golang编译运行版本对比

前文使用java+graalvm实现原生应用可观测监控: prometheus client_java实现进程的CPU、内存、IO、流量的可观测,但是部分java依赖包使用了复杂的反射功能,Graalvm编译可能失败,无法在运行过程中获取反射类,需要手动添加反射类,比较麻烦,容易出现编译原生失败的情况。
这里介绍基于Prometheus的client_golang库实现应用可观测监控,使用Go语言实现,编译更简单。
官方教程:[https://prometheus.io/docs/guides/go-application/](Instrumenting a Go application for Prometheus)
client_golang: https://github.com/prometheus/client_golang

1. 安装client_golang库

当前最新版本v1.20.5

go get github.com/prometheus/client_golang/prometheus
go get github.com/prometheus/client_golang/prometheus/promauto
go get github.com/prometheus/client_golang/prometheus/promhttp

2. 编写可观测监控代码

实现进程的CPU、内存、IO、流量的可观测监控,部分实现代码如下:

package metricsimport ("bufio""container/list""encoding/json""errors""fmt""github.com/prometheus/client_golang/prometheus""os/exec""task-exporter/common""task-exporter/models""regexp""runtime""strconv""strings"
)type TopMetrics struct{}var Registry = prometheus.NewRegistry()var upGauge = prometheus.NewGauge(prometheus.GaugeOpts{Name: METRICS_UP_USE,Help: "help",
})var processCpuGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: METRICS_CPU_USE,Help: "help",
}, []string{LABEL_PID, LABEL_USER, LABEL_CMD, LABEL_INCLUDE})var processMemGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: METRICS_MEM_USE,Help: "help",
}, []string{LABEL_PID, LABEL_USER, LABEL_CMD, LABEL_INCLUDE})var processResGauge = prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: METRICS_RES_USE,Help: "help",
}, []string{LABEL_PID, LABEL_USER, LABEL_CMD, LABEL_INCLUDE})func init() {upGauge.Set(1)Registry.MustRegister(upGauge)Registry.MustRegister(processCpuGauge)Registry.MustRegister(processMemGauge)Registry.MustRegister(processResGauge)fmt.Println("=====init=====")
}func (top *TopMetrics) Run() {topData, _ := top.handle()processList := topData.ProcessListvar elements []models.ProcessInfofor e := processList.Front(); e != nil; e = e.Next() {elements = append(elements, e.Value.(models.ProcessInfo))}elements = top.topCpuMem(elements, "cpu")processCpuGauge.Reset()for row, v := range elements {if row < common.ConfigInfo.Limit {processCpuGauge.WithLabelValues(v.Pid, v.User, v.Cmd, v.In).Set(v.Cpu)}}// MEM,RESelements = top.topCpuMem(elements, "res")processMemGauge.Reset()processResGauge.Reset()for row, v := range elements {if row < common.ConfigInfo.Limit {processMemGauge.WithLabelValues(v.Pid, v.User, v.Cmd, v.In).Set(v.Mem)processResGauge.WithLabelValues(v.Pid, v.User, v.Cmd, v.In).Set(v.Res)}}}func (top *TopMetrics) handle() (models.TopData, error) {var topData = models.TopData{ProcessList: list.New()}// 创建一个 Command 对象,指定要执行的外部命令及其参数cmd := exec.Command("top", "-c", "-b", "-n", "1", "-w", "512")// 获取命令的标准输出stdout, err := cmd.StdoutPipe()defer stdout.Close()if err != nil {fmt.Println("Error creating StdoutPipe:", err)return topData, errors.New("Error creating StdoutPipe:")}// 启动命令if err := cmd.Start(); err != nil {fmt.Println("Error starting command:", err)return topData, errors.New("Error starting command")}// 使用 bufio.Scanner 逐行读取命令的输出scanner := bufio.NewScanner(stdout)//fmt.Println("\n=====start=====")row := 1for scanner.Scan() {line := scanner.Text()//fmt.Println(row, "======:", line)if row == 1 {//top.handleUptime(line, row, &topData)} else if row == 2 {//top.handleTask(line, row, &topData)} else if row == 3 {//top.handleCpu(line, row, &topData)} else if row == 4 {//top.handleMem(line, row, &topData)} else if row == 5 {//top.handleSwap(line, row, &topData)} else if row >= 8 {top.handleProcess(line, row, &topData)}row++}// 等待命令执行完成if err := cmd.Wait(); err != nil {fmt.Println("Error waiting for top command to finish:", err)return topData, errors.New("exec: not started")}// 检查扫描过程中是否有错误if err := scanner.Err(); err != nil {fmt.Println("Error reading output:", err)}return topData, nil
}func (top *TopMetrics) handleProcess(line string, row int, topData *models.TopData) {//                                       pid      user      PR       NI    VIRT      RES     SHR     S        %CPU        %MEM         TIME    COMMANDprocessRegex := regexp.MustCompile("(\\d+)\\s+(\\S+)\\s+\\S+\\s+\\S+\\s+\\S+\\s+(\\S+)\\s+\\S+\\s+\\S+\\s+([\\d.]+)\\s+([\\d.]+)\\s+\\S+\\s(.+)")processMatches := processRegex.FindStringSubmatch(line)if len(processMatches) == 7 {process := models.ProcessInfo{In: "n"}process.Pid = processMatches[1]process.User = processMatches[2]res := processMatches[3]if strings.HasSuffix(res, "m") {process.Res, _ = strconv.ParseFloat(strings.Trim(res, "m"), 64)process.Res = process.Res * 1024} else if strings.HasSuffix(res, "g") {process.Res, _ = strconv.ParseFloat(strings.Trim(res, "g"), 64)process.Res = process.Res * 1024 * 1024} else {process.Res, _ = strconv.ParseFloat(res, 64)}process.Cpu, _ = strconv.ParseFloat(processMatches[4], 64)process.Mem, _ = strconv.ParseFloat(processMatches[5], 64)process.Cmd = strings.TrimSpace(processMatches[6])// 检查别名process.Cmd = common.FilterAlias(process.Cmd)topData.ProcessList.PushBack(process)} else {strB, _ := json.Marshal(processMatches)fmt.Println(row, "======processRegex found:", string(strB))}
}/*** 采集进程信息CPU\MEM\RES*/
func (top *TopMetrics) topCpuMem(processes []models.ProcessInfo, ptype string) []models.ProcessInfo {len := len(processes)//fmt.Println("======topCpuMem len:", len)for i := 0; i < len-1; i++ {for r := i + 1; r < len; r++ {if ptype == "cpu" {if processes[r].Cpu > processes[i].Cpu {processes[i], processes[r] = processes[r], processes[i]}} else if ptype == "mem" {if processes[r].Mem > processes[i].Mem {processes[i], processes[r] = processes[r], processes[i]}} else if ptype == "res" {if processes[r].Res > processes[i].Res {//fmt.Println("======res change:", i, processes[i], r, processes[r])processes[i], processes[r] = processes[r], processes[i]}}}}return processes
}

main.go

package mainimport ("flag""github.com/prometheus/client_golang/prometheus/promhttp""log""net/http""task-exporter/metrics""time"
)var addr = flag.String("listen-address", ":8080", "The address to listen on for HTTP requests.")func main() {registry := metrics.Registrygo func() {for {top := metrics.TopMetrics{}top.Run()//io := metrics.IoMetrics{}//io.Run()//net := metrics.NethogsMetrics{}//net.Run()//port := metrics.NetstatMetrics{}//port.Run()time.Sleep(15 * time.Second)}}()http.Handle("/metrics", promhttp.HandlerFor(registry,promhttp.HandlerOpts{EnableOpenMetrics: true,}),)log.Printf("Listening on http://localhost%s/metrics", *addr)log.Fatal(http.ListenAndServe(*addr, nil))
}

3. 运行效果

在这里插入图片描述
Grafana展示效果参看前文。

4. jar、graalvm、golang编译运行版本对比

jar、graalvm、golang生成文件大小对比
在这里插入图片描述
jar、graalvm、golang运行占用CPU、内存对比
在这里插入图片描述

go编译版本:task_exporter-linux-x86.zip

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/466578.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity3D UI 拖拽

Unity3D 实现 UI 元素拖拽功能。 UI 拖拽 通常画布上的 UI 元素都是固定位置的&#xff0c;我们可以通过实现拖拽接口&#xff0c;让 UI 元素可以被拖拽到其他位置。 拖拽接口 创建一个脚本 UIDrag.cs&#xff0c;在默认继承的 MonoBehaviour 后面&#xff0c;再继承三个接…

《重学Java设计模式》之 工厂方法模式

《重学Java设计模式》之 建造者模式 《重学Java设计模式》之 原型模式 《重学Java设计模式》之 单例模式 模拟发奖多种商品 工程结构 奖品发放接口 package com.yys.mes.design.factory.store;public interface ICommodity {/*** Author Sherry* Date 14:20 2024/11/6**/voi…

【Python爬虫实战】DrissionPage 与 ChromiumPage:高效网页自动化与数据抓取的双利器

&#x1f308;个人主页&#xff1a;易辰君-CSDN博客 &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、DrissionPage简介 &#xff08;一&#xff09;特点 &#xff08;二&#xff09;安装 &#xff08;三…

Word大珩助手:超大数字怎么读?35位数字?69位数字?

俄罗斯日前对谷歌开出了20000000000000000000000000000000000&#xff08;35位数字&#xff09;美元的罚款 这一数字远超全球GDP总和&#xff0c;消息一出很快就登上热搜。 面对这样一个庞大的数字&#xff0c;人们不禁好奇&#xff0c;这样的数字该如何读出来&#xff1f; …

Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized

这里是Themberfue 在上一节的最后&#xff0c;我们讨论两个线程同时对一个变量累加所产生的现象 在这一节中&#xff0c;我们将更加详细地解释这个现象背后发生的原因以及该如何解决这样类似的现象 线程安全问题 public class Demo15 {private static int count 0;public …

17、论文阅读:VMamba:视觉状态空间模型

前言 设计计算效率高的网络架构在计算机视觉领域仍然是一个持续的需求。在本文中&#xff0c;我们将一种状态空间语言模型 Mamba 移植到 VMamba 中&#xff0c;构建出一个具有线性时间复杂度的视觉主干网络。VMamba 的核心是一组视觉状态空间 (VSS) 块&#xff0c;搭配 2D 选择…

JavaAPI(1)

Java的API&#xff08;1&#xff09; 一、Math的API 是一个帮助我们进行数学计算的工具类私有化构造方法&#xff0c;所有的方法都是静态的&#xff08;可以直接通过类名.调用&#xff09; 平方根&#xff1a;Math.sqrt()立方根&#xff1a;Math.cbrt() 示例&#xff1a; p…

【362】基于springboot的在线租房和招聘平台

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统在线租房和招聘平台信息管理难度大&#xff0c;容错率低&…

华为HCIP —— QinQ技术实验配置

一、QinQ的概述 1.1QinQ的概念 QinQ&#xff08;802.1Q in 802.1Q&#xff09;技术是一项扩展VLAN空间的技术&#xff0c;通过在原有的802.1Q报文基础上再增加一层802.1Q的Tag来实现。 1.2QinQ封装结构 QinQ封装报文是在无标签的以太网数据帧的源MAC地址字段后面加上两个VL…

【数据集】【YOLO】【目标检测】抽烟识别数据集 6953 张,YOLO/VOC格式标注,吸烟检测!

数据集介绍 【数据集】抽烟识别数据集 6953 张&#xff0c;目标检测&#xff0c;包含YOLO/VOC格式标注。数据集中包含1种分类&#xff1a;“smoking”。数据集来自国内外图片网站和视频截图。检测范围园区吸烟检测、禁烟区吸烟检测、监控吸烟检测、无人机吸烟检测等。 主页私…

赛元MCU 脱机烧录步骤

烧录设置 生成烧录配置文件 载入配置文件 下载程序到烧录器中 并 对比 脱机烧录 1、 将SC-LINK 使用外部5V电源供电 2、将烧录口对准主板烧录接口 3、busy亮红灯&#xff0c;进入烧录ing&#xff0c;烧录成功后&#xff0c;OK灯亮蓝灯 注意事项 其中工程校验和 可以作为程序…

leetcode字符串(二)-重复的子字符串

题目 459.重复的子字符串 给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: …

langchain 4大组件 | AI应用开发

在人工智能的浪潮中&#xff0c;大型语言模型&#xff08;LLM&#xff09;逐渐成为推动科技进步的重要力量。而LangChain&#xff0c;作为一个专为LLM应用开发设计的框架&#xff0c;凭借其模块化和高效性&#xff0c;受到了广泛关注。本文将深入浅出地讲解LangChain中的四个基…

TensorFlow|咖啡豆识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 &#x1f37a; 要求&#xff1a; 自己搭建VGG-16网络框架调用官方的VGG-16网络框架 &#x1f37b; 拔高&#xff08;可选&#xff09;&#xff1a; 验证集准…

Jmeter5.X性能测试

Jmeter5.X性能测试 文章目录 Jmeter5.X性能测试一、掌握Http基础协议1.1 浏览器的B/S架构和C/S架构1.2 HyperText Transfer Protocol 超文本传输协议1.3 超文本传输协议Http消息体拆分讲解1.4 HTTP的九种请求方法和响应码介绍1.5 Http请求头/响应头1.6 Http常见请求/响应头cont…

信息安全工程师(81)网络安全测评质量管理与标准

一、网络安全测评质量管理 遵循标准和流程 网络安全测评应严格遵循国家相关标准和流程&#xff0c;确保测评工作的规范性和一致性。这些标准和流程通常包括测评方法、测评步骤、测评指标等&#xff0c;为测评工作提供明确的指导和依据。 选择合格的测评团队 测评团队应具备相关…

AI - 人工智能;Ollama大模型工具;Java之SpringAI(三)

AI - 人工智能&#xff1b;Java之SpringAI&#xff08;一&#xff09; AI - 人工智能&#xff1b;Java之SpringAI&#xff08;二&#xff09; 一、Ollama 官网&#xff1a;https://ollama.com/ Ollama是一个大模型部署运行工具&#xff0c;在该工具里面可以部署运行各种大模型…

力扣—不同路径(路径问题的动态规划)

文章目录 题目解析算法原理代码实现题目练习 题目解析 算法原理 状态表示 对于这种「路径类」的问题&#xff0c;我们的状态表示⼀般有两种形式&#xff1a; i. 从[i, j] 位置出发。 ii. 从起始位置出发&#xff0c;到[i, j] 位置。 这⾥选择第⼆种定义状态表⽰的⽅式&#xf…

用了Stream后,代码反而越写越丑?

使用 Stream API 可以使代码更加简洁和易读&#xff0c;但如果不恰当地使用或过度使用&#xff0c;确实可能导致代码变得复杂和难以理解。以下是一些常见的问题和改进建议&#xff1a; 常见问题 过度链式调用&#xff1a;过度链式调用 Stream 方法会导致代码行过长&#xff0c…

论文速读:简化目标检测的无源域适应-有效的自我训练策略和性能洞察(ECCV2024)

中文标题&#xff1a;简化目标检测的无源域适应&#xff1a;有效的自我训练策略和性能洞察 原文标题&#xff1a;Simplifying Source-Free Domain Adaptation for Object Detection: Effective Self-Training Strategies and Performance Insights 此篇文章为论文速读&#xff…