异常追踪与 JIRA 实现双向联动最佳实践


异常追踪 是观测云推出的、基于内部异常有效协调的沟通管理工具。

JIRA 为企业内部项目管理工具。

当应用程序或系统出现异常时,通常需要及时处理以保证系统的正常运行。通过异常追踪与 JIRA 双向联动,可以让企业内部相关人员快速了解、分析问题故障发生的原因、追溯并记录故障的处理过程,有效提高人员的沟通效率,极大降低了故障处理成本。

准备工作

Jira

获取 Jira 平台对应项目的 project、项目地址、api_token、username,后续观测云脚本需要用到。

只有管理员才有权限进行以上操作

观测云

创建 API Key

API Key 可参考文档 API Key

其中 key name 设置为 Jira 系统,有利于区分该评论信息来源于观测云或者是 Jira,且 key name 会作为 user 展示在观测云 issue 当中。

Func 脚本编写

  • 登陆 Func

登陆到已经部署的Dataflux Func 观测云特别版

  • 添加 Python 依赖
  1. 点击 管理 菜单
  2. 点击 实验性功能 ,打开启用 PIP 工具开关,如已开启,请忽略此步骤。
  3. 点击 PIP 工具 ,安装 Python 包 ,填入jira ,选择默认数据源即可,如果默认数据源没有当前依赖,可以切换其他数据源,点击安装按钮,完成依赖安装操作。
  • 编写脚本
  1. 点击 开发 菜单;
  2. 点击 新建脚本集 按钮,填写脚本ID ,可以自定义,这里填写Issue_to_jira,点击 保存按钮;
  3. 选择 Issue_to_jira,点击新建脚本,这个ID 也可以随便写;
  4. 粘贴以下脚本内容,调整配置信息。
python 复制代码
import requests
import json
import time
from datetime import datetime, timedelta
from jira import JIRA

# 观测云配置,注意修改df_api_key
base_url = 'https://openapi.guance.com'
channel_list_url = base_url + '/api/v1/channel/quick_list'
issue_list_url = base_url + '/api/v1/issue/list'
create_issue_reply_url = base_url + '/api/v1/issue/reply/create'
df_api_key = 'vy2EV......fuTtn'

# JIRA配置,以下配置均为必填项,修改为自己的环境
username = 'sutt'
api_token = 'ATATT3xFfGF0eVvhZUkO0tTas8JnNYEsxGIJqWGinVyQL0ME......B6E'
jira_server_url = 'https://***.net/'
project_key = 'projectName'

#连接JIRA
def connect_to_jira(username, api_token, jira_server_url):
    try:
        jira_connection = JIRA(basic_auth=(username, api_token), server=jira_server_url)
        print("成功连接到JIRA!")
        return jira_connection
    except Exception as e:
        print(f"连接JIRA出错: {e}")
        return None

jira_instance = connect_to_jira(username, api_token, jira_server_url)

def sync_issues_from_guance_to_jira():
    headers = {
        'DF-API-KEY': df_api_key,
        'Content-Type': 'application/json;charset=UTF-8'
    }

    one_minute_ago = datetime.now() - timedelta(minutes=1)
    one_minute_ago_time = int(one_minute_ago.timestamp())
    current_time = int(time.time())

    response = requests.get(channel_list_url, headers=headers)
    if response.status_code == 200:
        channel_list = response.json()["content"]
        for channel in channel_list:
            if channel["name"] == "default":
                body = {
                    'channelUUID': channel["uuid"],
                    'startTime': one_minute_ago_time,
                    'endTime': current_time
                }
                issue_response = requests.post(issue_list_url, headers=headers, data=json.dumps(body))
                print(issue_response.text)  # 打印响应内容,帮助调试

                if issue_response.status_code == 200:
                    issue_lists = issue_response.json()['content']
                    for issue in issue_lists:
                        issue_uuid = issue["uuid"]
                        print(f"UUID from Guance: {issue_uuid}")  # 打印 UUID 调试

                        issue_data = {
                            'project': {'key': project_key},
                            'summary': issue["name"],
                            'description': issue["description"],
                            'issuetype': {'name': '缺陷'},
                            'priority': {'name': 'Medium'},
                            'labels': [issue_uuid]  # 使用label来存储issue_id
                        }
                        created_issue = jira_instance.create_issue(fields=issue_data)
                        print(f"Created JIRA issue: {created_issue.key}")

def create_issue_reply(issue_uuid, content):
    headers = {
        'DF-API-KEY': df_api_key,
        'Content-Type': 'application/json;charset=UTF-8'
    }
    body = {
        'issueUUID': issue_uuid,
        'content': content,
        'extend': {}
    }
    response = requests.post(create_issue_reply_url, headers=headers, data=json.dumps(body))
    if response.status_code == 200:
        print(f"Successfully created a reply for issueUUID: {issue_uuid}")
    else:
        print(f"Failed to create a reply for issueUUID: {issue_uuid}. Status code: {response.status_code}")

def sync_comments_from_jira_to_guance():
    end_time = datetime.now()
    start_time = end_time - timedelta(minutes=1)
    start_time_str = start_time.strftime('%Y-%m-%d %H:%M')
    end_time_str = end_time.strftime('%Y-%m-%d %H:%M')

    jql_str = f'project = {project_key} AND updated >= "{start_time_str}" AND updated <= "{end_time_str}"'
    recently_updated_issues = jira_instance.search_issues(jql_str)

    has_updates = False
    for issue in recently_updated_issues:
        comments = jira_instance.comments(issue)
        new_comments = [comment for comment in comments if start_time_str <= comment.created.split('.')[0].replace("T", " ") <= end_time_str]

        issue_labels = issue.fields.labels
        guance_issue_id = None
        for label in issue_labels:
            if label.startswith("issue"):
                guance_issue_id = label
                break

        if guance_issue_id and new_comments:
            has_updates = True
            for comment in new_comments:
                create_issue_reply(guance_issue_id, comment.body)

    if not has_updates:
        print("在过去的一分钟内没有更新的事务或者新的评论。")

@DFF.API('Create_JIRA_Issue_Reply2')
def guance():
    print("do start")
    sync_issues_from_guance_to_jira()
    sync_comments_from_jira_to_guance()
  • 发布脚本

点击发布按钮即完成发布。发布完成后,表示 API 已经发布成功,可以对外进行服务。

  • 自动触发配置

自动触发配置 可以定时执行 API。

  1. 管理 菜单进入,点击自动触发配置按钮;
  2. 点击右上角新建按钮进行新建;
  3. 选择执行的脚本,参数可以不指定,勾选对应的执行频率,这里调整为按每分钟重复保存即可。

创建 issue

观测云有两种创建 issue 的方式

  • 直接创建
  • 通过监控器创建

直接创建

  1. 登陆观测云控制台
  2. 点击异常追踪 菜单,点击右上角新建Issue按钮,填写 issue 信息,保存即可。

通过监控器创建

通过监控器创建即通过监控器产生事件信息,进行创建issue。

  1. 登陆观测云控制台
  2. 点击左侧监控菜单
  3. 可以新增监控器,也可以调整原有的监控器。编辑对应的监控器,开启同步创建 Issue开关,保存。

效果图

Jira 效果:

自动产生了 Jira issue,当进行评论后,可以在观测云上展示 issue 的处理过程。

观测云效果

观测云上也会同步 Jira issue 处理过程。

相关推荐
Bs_MoneyMagnet3 小时前
基于springboot+vue的滑雪场票务与装备租赁系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring·毕业设计·计算机毕业设计
AlienZHOU7 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
狗头大军之江苏分军10 小时前
《潮水漫过十七岁》开学了
后端
我要见SA姐110 小时前
告别 Copilot?Codex 本地化部署指南
运维·数据库·机器学习·oracle·回归
苏三说技术10 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong11 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno70411 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc11 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
Elastic 中国社区官方博客11 小时前
列式存储并不等同于列式数据库。Columnar 模式为 Elasticsearch 带来了什么
大数据·运维·数据库·elasticsearch·搜索引擎
aramae12 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端