python拉取grafana监控图形

python通过grafana提供的api接口拉取grafana监控图形并保存至word文档生成日报发送邮件

前置条件:

1.grafana平台需要安装grafana-image-renderer 插件,用于生成静态图形

页面可以检查是否已安装

未安装会进入如下页面:

从API接口拉取图片会提示:

安装方式参考:

https://grafana.com/grafana/plugins/grafana-image-renderer/

该插件对内存大小有一定要求:

如果已安装该插件,点击Direct link rendered image后会显示一个静态监控图形页面

参考: https://cloud.tencent.com/document/product/1437/65674

2.在grafana页面生成api_keys,用于接口请求认证

不同版本获取方式不同 此示例为V9.2.6版,入口如下:

点击Add API key添加,可以指定有效期,弹出密钥的界面记得把密钥复制下来,否则关闭后就看不到了。

代码示例:

  • 该示例是将Grafana获取的多张图形保存到本地的panels目录下(多线程执行),
  • 通过python的Image模块进行图片拼接(拼接方式可自定义),
  • 读取日志模版文档(模版中预留了等字符用于定位),
  • 将拼好的图片插入到日志模版文档并替换文档中的日期信息,
  • 保存生成新的文档,删除本地panels目录下的图片缓存,并发送邮件。
# -*- coding: UTF-8 -*-
import smtplib
import requests
import os
import shutil
import time
from PIL import Image
from docx import Document
from docx.shared import Inches
from datetime import datetime, timedelta
from concurrent.futures import ThreadPoolExecutor, as_completed
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import make_header # 配置 Grafana API 参数
GRAFANA_HOST = "http://xxxxxxxxxxx"
# Grafana API 密钥具有时效性,如过期,请联系运维人员生成新的api_keys
API_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 仪表板ID
DASHBOARD_UID = "xxxxxxxxxx"
# 图形ID
PANEL_ID_DATA = {"PANEL_1":[30,31,2,10,12,14,16,18,20,22,24,26,28],
"PANEL_2":[37, 39, 41, 43, 45, 47, 49, 51, 53],}
ORG_ID = "1"
#日志模版文件
document_path = "xxxxxxxx日志 - 模板.docx"
# 邮箱接收人
RECEIVERS = ["xxxxxx.com", "xxx.com"]
# 保存图片的文件名
folder = "panels" #邮件发送
def send_mail(filename):
sender = 'xxxxxxx.com'
receiver = ','.join(RECEIVERS)
smtpserver = 'xxxxxx.com'
user = 'xxxxxx.com'
password = 'xxxxxxxx'
mail_title = filename.split('/')[1]
mail_title = mail_title.split('.')[0]
# 创建一个带附件的实例
message = MIMEMultipart()
message['From'] = sender
message['To'] = receiver
message['Subject'] = Header(mail_title, 'utf-8') # 邮件正文内容
message.attach(MIMEText(f'hello,附件为 {mail_title},请查收,如有问题请与我联系。', 'plain', 'utf-8'))
# 构造附件
file_msg = MIMEText(open(filename, 'rb').read(), 'base64', 'UTF-8')
file_msg["Content-Type"] = 'application/octet-stream;name="%s"' % make_header([(filename, 'UTF-8')]).encode('UTF-8')
file_msg["Content-Disposition"] = 'attachment;filename= "%s"' % make_header([(filename, 'UTF-8')]).encode('UTF-8')
message.attach(file_msg)
try: smtpObj = smtplib.SMTP(smtpserver)
smtpObj.starttls()
smtpObj.login(user, password)
smtpObj.sendmail(sender, receiver, message.as_string())
print("邮件发送成功!!!")
except Exception as e:
print(e)
print("邮件发送失败!!!")
finally:
smtpObj.quit() def center_insert_img(doc, img,date_str):
"""插入图片"""
date_obj = datetime.strptime(date_str, '%Y-%m-%d')
# 将datetime对象格式化为指定的中文格式字符串
formatted_date = date_obj.strftime('%Y年%m月%d日')
for paragraph in doc.paragraphs:
# 根据文档中的占位符定位图片插入的位置
if '<datetime>' in paragraph.text:
paragraph.text = paragraph.text.replace('<datetime>', formatted_date)
elif '<img1>' in paragraph.text:
# 把占位符去掉
paragraph.text = paragraph.text.replace('<img1>', '')
# 添加一个文字块
run = paragraph.add_run('')
# 添加一个’回车换行效果‘
run.add_break()
# 添加图片并指定大小
run.add_picture(img[0], width=Inches(6.2))
elif '<img2>' in paragraph.text:
# 把占位符去掉
paragraph.text = paragraph.text.replace('<img2>', '')
# 添加一个文字块
run = paragraph.add_run('')
# 添加一个’回车换行效果‘
run.add_break()
# 添加图片并指定大小
run.add_picture(img[1], width=Inches(6.2)) def save_img_to_doc(img,day_time):
"""把图片保存到doc文件中的指定位置"""
tpl_doc = document_path
current_year = datetime.now().year
if not os.path.exists(f"{current_year}_doc"):
os.makedirs(f"{current_year}_doc")
res_doc = f'{current_year}_doc/日志报告_{day_time}.docx'
# 打开模板文件
document = Document(tpl_doc)
# 插入图片居中
center_insert_img(document, img,day_time)
# 保存结果文件
document.save(res_doc)
return res_doc def download_image(render_url, output_path, headers):
"""下载单张图片的函数"""
try:
response = requests.get(render_url, headers=headers, stream=True)
if response.status_code == 200 and "image/png" in response.headers.get("Content-Type", ""):
with open(output_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
return output_path
else:
print(f"获取图形失败: {render_url}")
print(f"状态码: {response.status_code}, 返回内容: {response.text}")
return None
except Exception as e:
print(f"下载图片出错: {e}")
return None def merge_images(image_paths, output_path, layout):
"""合并图片""" images = [Image.open(path) for path in image_paths]
width, height = images[0].size
new_image = object
if layout == "grid_3xN":
num_rows = (len(images) + 2) // 3
new_image = Image.new('RGB', (3 * width, num_rows * height))
for idx, img in enumerate(images):
x, y = (idx % 3) * width, (idx // 3) * height
new_image.paste(img, (x, y))
elif layout == "grid_3x3":
new_image = Image.new('RGB', (3 * width, 3 * height))
for idx, img in enumerate(images[:9]):
x, y = (idx % 3) * width, (idx // 3) * height
new_image.paste(img, (x, y)) new_image.save(output_path)
new_image.close() def download_grafana_panel():
# start = time.time()
time_tuple = generate_daily_timestamps_and_dates()
image_paths = []
save_img_to_doc_paths = []
headers = {"Authorization": f"Bearer {API_TOKEN}"}
tasks = [] # 创建下载目录
daily_folder = f"{folder}/{time_tuple[0]}"
os.makedirs(daily_folder, exist_ok=True) # 使用线程池并行下载图片
# 此处的的URL仅供参考,I6xasdas要替换为你页面的实际值
# 也就是你点击Direct link rendered image后显示的静态监控图形页面的URL
with ThreadPoolExecutor(max_workers=5) as executor:
for PANEL_NAME, PANEL_ID_list in PANEL_ID_DATA.items():
for PANEL_ID in PANEL_ID_list:
render_url = f'{GRAFANA_HOST}/render/d-solo/I6xasdas/{DASHBOARD_UID}?orgId=1&from={time_tuple[1]}&to={time_tuple[2]}&panelId={PANEL_ID}&width=1000&height=500&tz=Asia%2FShanghai'
output_path = f"{daily_folder}/{DASHBOARD_UID}_panel_{PANEL_ID}.png"
tasks.append(executor.submit(download_image, render_url, output_path, headers)) # 收集任务结果
for future in as_completed(tasks):
result = future.result()
if result:
image_paths.append(result) # 合并图片 (第一组 3xN)
if len(image_paths) > 0:
output_path1 = f"{daily_folder}/panel_01.jpg"
merge_images(image_paths[:13], output_path1, layout="grid_3xN")
save_img_to_doc_paths.append(output_path1) # 合并图片 (第二组 3x3)
if len(image_paths) > 13:
output_path2 = f"{daily_folder}/panel_02.jpg"
merge_images(image_paths[12:21], output_path2, layout="grid_3x3")
save_img_to_doc_paths.append(output_path2) # 插入文档保存
doc_file_path = save_img_to_doc(save_img_to_doc_paths, time_tuple[0])
# 删除缓存图片
remove_dir(f"{folder}/{time_tuple[0]}")
#发送邮件
send_mail(doc_file_path)
# end_time = time.time() - start
# print(f"巡检报告成功保存并删除图片缓存!耗时{round(end_time,2)}秒") def generate_daily_timestamps_and_dates():
current_date_time = datetime.now()
# 提取日期部分并格式化为年-月-日的字符串形式
formatted_date = current_date_time.strftime('%Y-%m-%d')
# 将输入的日期字符串转换为datetime对象
start_date = datetime.strptime(formatted_date, '%Y-%m-%d')
last_day_start_date = start_date - timedelta(days=1) # 获取当天的起始时间(将时间设置为00:00:00)
start_of_day = last_day_start_date.replace(hour=0, minute=0, second=0, microsecond=0)
# 将datetime对象转换为时间戳(单位:秒)
timestamp = int(start_of_day.timestamp()*1000)
date_str = start_of_day.strftime('%Y-%m-%d') return (date_str, timestamp, timestamp + 86399*1000) def remove_dir(directory):
try:
shutil.rmtree(directory)
except OSError as e:
print(f"删除目录时出错: {e}")
if e.errno == 32: # 文件正在被占用
print("文件被占用,等待释放后重试...")
time.sleep(0.1) # 等待 0.1 秒后再次尝试
try:
shutil.rmtree(directory)
print(f"第二次尝试删除成功: {directory}")
except Exception as e2:
print(f"仍然无法删除目录: {e2}") if __name__ == "__main__":
download_grafana_panel()

python拉取grafana监控图形的更多相关文章

  1. 一步步教你用Prometheus搭建实时监控系统系列(二)——详细分析拉取和推送两种不同模式

    前言 本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于自己的实时监控告警平台. 本系列受众对象为初次接触Prometheus的用户,大神勿喷,偏重于操作和实战,但是重要的概念 ...

  2. python自动拉取备份压缩包并删除3天前的旧备份

    业务场景,异地机房自动拉取已备份好的tar.gz数据库压缩包,并且只保留3天内的压缩包文件,用python实现 #!/usr/bin/env python import requests,time,o ...

  3. Python 一键拉取Git分支源码自动解析并执行SQL语句

    基于Python实现自动拉取Git分支源码自动解析并执行SQL语句 by:授客 QQ:1033553122 1.代码用途 开发过程中,研发人员会提交SQL更新脚本到Git源码库,然后测试负责去拉取这些 ...

  4. 分布式监控系统Zabbix--使用Grafana进行图形展示

      今天介绍一款高颜值监控绘图工具Grafana,在使用Zabbix监控环境中,通常我们会结合Grafana进行图形展示.Grafana默认没有zabbix作为数据源,需要手动给zabbix安装一个插 ...

  5. Centos 7安装Grafana 4及结合Zabbix3.2实现可视化监控图形

    上一篇介绍了如何在Centos 7环境下安装zabbix监控,本章继续介绍在Centos 7环境下安装Grafana,并结合Zabbix实现可视化监控图形! 简介: Grafana 是 Graphit ...

  6. Python使用又拍云进行第三方文件拉取

    在爬虫过程中,需要将图片或其他文件进行存储到云上,但在下载图片时,看官方文档,貌似需要先下载到后再上传又拍云,感觉效率很低下.经查找资料实现Python直接对第三方资源进行文件拉取操作,即不需要下载到 ...

  7. python 写了一个批量拉取文件进excel文档

    路径如: C:\\Users\\huaqi\\Desktop\\信息收集 “信息收集”目录下有以下子目录:[技术,客服,运营,行政] “技术”目录下有以下子文件:[小白.txt,小红.txt,小黑.t ...

  8. Ubuntu上Grafana 监控 Docker的技巧

    导读 Grafana 是一个有着丰富指标的开源控制面板.在可视化大规模测量数据的时候是非常有用的.根据不同的指标数据,它提供了一个强大.优雅的来创建.分享和浏览数据的方式. 它提供了丰富多样.灵活的图 ...

  9. kubernetes(k8s) Prometheus+grafana监控告警安装部署

    主机数据收集 主机数据的采集是集群监控的基础:外部模块收集各个主机采集到的数据分析就能对整个集群完成监控和告警等功能.一般主机数据采集和对外提供数据使用cAdvisor 和node-exporter等 ...

  10. Prometheus Grafana监控全方位实践

    这次就不用 docker 部署服务了,这样大家会更容易接受.欢迎阅读. 引言 Prometheus 是一个监控系统,也是一个时间序列数据库,用Go语言开发的,官方文档.通过从某些特定的目标如主机,My ...

随机推荐

  1. AI构建新质生产力,合合信息Embedding模型助力专业知识应用

    一.合合信息acge模型获MTEB中文榜单第一   现阶段,大语言模型的飞速发展吸引着社会各界的目光,背后支撑大型语言模型应用落地的Embedding模型也成为业内关注的焦点.近期,合合信息发布了文本 ...

  2. CSIG企业行-走进合合信息成功举行,聚焦生成式人工智能、智能文档处理前沿热点

    3月18日,由中国图象图形学学会(CSIG)主办,合合信息.CSIG文档图像分析与识别专业委员会联合承办的"CSIG企业行"系列活动成功举办.此次活动以"图文智能处理与多 ...

  3. MyBatis——使用Mapper代理开发

    使用 Mapper 代理开发方式完成入门案例   1.定义与SQL映射文件同名的Mapper接口,并将 Mapper 接口和SQL映射文件放置在同一目录下       (企业开发中,通常是将配置文件统 ...

  4. 2024 ByteCTF

    ByteCTF 极限逃脱 题目描述:本题需要通过动态调试分析出要输入的内容,可能在某些地方会有提示出现. 这是一个IOS逆向,因为没有设备只能静态分析 流程和安卓逆向大概一致 解压拖进ida 提示输入 ...

  5. 排查maven 冲突及解决方式

    Maven Maven 是一个以项目为中心的自动化构建工具,主要用于Java项目的管理和构建.它提供了一种统一的方式来描述项目的结构.依赖关系和构建过程,简化了项目的构建和管理. Maven 的主要特 ...

  6. 【赵渝强老师】Kafka的体系架构

    一.什么是Kafka? 数据工程中最具挑战性的部分之一是如何从不同点收集和传输大量数据到分布式系统进行处理和分析.需要通过消息队列正确地分离大量数据,因为如果一部分数据无法传送,则可以在系统恢复时传输 ...

  7. SVN(Linux)提交时强制写日志

    SVN(Linux)提交时强制写日志 1.创建并修改pre-commit文件 进入svn/code/hooks目录,在svn版本库的hooks文件夹下面,复制模版pre-commit.tmplcp p ...

  8. Linux-USB驱动笔记-Gadget Function驱动

    1.前言 在Linux-USB驱动笔记(四)–USB整体框架中有説到Gadget Function驱动,下面我们来具体看一下. Gadget Function就是指设备的功能,比如作为U盘,需要文件存 ...

  9. /proc/pids/smaps

    Linux内存管理 -- /proc/{pid}/smaps讲解 基本介绍 /proc/PID/smaps 文件是基于 /proc/PID/maps 的扩展,他展示了一个进程的内存消耗,比同一目录下的 ...

  10. webpack中 loader和plugin的区别

    首先 ,loader 是文件加载器,能够加载资源文件,并对文件进行一些处理,如翻译,压缩 ,最终一起打包到指定的文件中 :loader 运行在打包项目之前 : plugin 是插件 ,plugin赋予 ...