图表注释

图表注释(Chart Annotations)是添加到图表上的标签或备注,用于提供额外的信息或上下文。注释帮助澄清图表中呈现的数据,帮助查看者理解关键点或趋势。在 Uptrace 中,您可以通过 API 创建注释,将部署事件、故障事件等时间线事件与指标和追踪数据的变化关联起来。

概述

图表注释的主要作用:

  • 事件标记:标记部署、发布、故障等关键事件
  • 时间关联:将时间线事件与指标变化关联,便于分析因果关系
  • 团队协作:帮助团队成员理解图表中的异常点或趋势变化
  • 问题排查:通过注释快速定位问题发生的时间点

注释显示方式

Uptrace 在图表上以方形点(square dots)的形式显示注释,位于 X 轴(时间轴)上。点击注释可以查看注释的描述和标签。描述字段支持 Markdown 格式,可以包含指向其他系统的链接,提供更多详细信息。

创建注释

您可以通过发送 HTTP POST 请求到 Uptrace API 来创建注释。

API 接口

端点:https://api.uptrace.dev/api/v1/annotations

方法:POST

请求头:

  • Content-Type: application/json
  • uptrace-dsn: <YOUR_DSN>(必需)

请求体:JSON 格式

基本请求示例

使用 curl 创建注释:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H 'uptrace-dsn: <YOUR_DSN>' \
-H 'Content-Type: application/json' \
-d '{
"name": "Deployed to production",
"attrs": {
"service.version": "540d2ee"
}
}'

字段说明

注释的 JSON 请求体支持以下字段:

字段类型必需描述
namestring是注释名称,将显示在图表上
descriptionstring否注释描述文本,支持 Markdown 格式
colorstring否图表中使用的颜色,例如 green 或 #00ff00
attrsobject否键值对元数据,例如 {"deployment.environment": "production"}
fingerprintstring否用于去重的唯一字符串。如果存在相同 fingerprint 的注释,Uptrace 会忽略其他注释
timestring否覆盖注释时间,RFC3339 格式,例如 2024-01-15T10:30:00Z

字段详细说明

name(注释名称)

注释名称是必需的字段,将显示在图表上。建议使用简洁、描述性的名称。

示例:

{
"name": "Deployed to production",
"name": "v1.2.3 release",
"name": "Database migration completed"
}

description(描述)

描述字段支持 Markdown 格式,可以包含链接、列表、代码块等。这对于提供更多上下文信息非常有用。

示例:

{
"name": "Deployed to production",
"description": "Deployed version **v1.2.3** to production.\n\n- Fixed memory leak issue\n- Improved query performance\n\n[View release notes](https://github.com/example/releases/tag/v1.2.3)"
}

color(颜色)

颜色字段用于指定注释在图表中显示的颜色。可以使用颜色名称(如 green、red、blue)或十六进制颜色代码(如 #00ff00、#ff0000)。

示例:

{
"name": "Deployment",
"color": "green"
}
{
"name": "Incident",
"color": "#ff0000"
}

attrs(属性)

属性字段是一个键值对对象,用于存储与注释相关的元数据。这些属性可以用于过滤和分组注释。

常用属性:

  • service.name:服务名称
  • service.version:服务版本
  • deployment.environment:部署环境
  • deployment.name:部署名称

示例:

{
"name": "Deployed to production",
"attrs": {
"service.name": "api-service",
"service.version": "v1.2.3",
"deployment.environment": "production",
"deployment.name": "deploy-20240115"
}
}

fingerprint(指纹)

指纹字段用于去重。如果多个注释具有相同的 fingerprint,Uptrace 只会保留第一个,忽略后续的注释。这对于防止重复创建相同事件的注释非常有用。

示例:

{
"name": "Deployed to production",
"fingerprint": "v1.2.3",
"attrs": {
"service.version": "v1.2.3"
}
}

time(时间)

时间字段用于覆盖注释的时间戳。如果不提供,Uptrace 会使用当前时间。时间必须使用 RFC3339 格式。

示例:

{
"name": "Deployed to production",
"time": "2024-01-15T10:30:00Z",
"attrs": {
"service.version": "v1.2.3"
}
}

完整示例

创建一个完整的注释,包含所有字段:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H 'uptrace-dsn: <YOUR_DSN>' \
-H 'Content-Type: application/json' \
-d '{
"name": "Deployed to production",
"description": "Deployed version **v1.2.3** to production environment.\n\n**Changes:**\n- Fixed memory leak in cache layer\n- Improved database query performance by 30%\n- Added new authentication endpoint\n\n[View full changelog](https://github.com/example/releases/tag/v1.2.3)",
"color": "green",
"fingerprint": "deploy-v1.2.3-prod",
"time": "2024-01-15T10:30:00Z",
"attrs": {
"service.name": "api-service",
"service.version": "v1.2.3",
"deployment.environment": "production",
"deployment.name": "deploy-20240115",
"deployment.trigger": "manual"
}
}'

使用不同编程语言创建注释

Go 示例

package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Annotation struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Color string `json:"color,omitempty"`
Attrs map[string]string `json:"attrs,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Time string `json:"time,omitempty"`
}
func createAnnotation(dsn string, annotation Annotation) error {
url := "https://api.uptrace.dev/api/v1/annotations"
jsonData, err := json.Marshal(annotation)
if err != nil {
return err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("uptrace-dsn", dsn)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("failed to create annotation: %s", resp.Status)
}
return nil
}
func main() {
dsn := "https://your-token@api.uptrace.dev/your-project-id"
annotation := Annotation{
Name: "Deployed to production",
Description: "Deployed version **v1.2.3** to production.",
Color: "green",
Fingerprint: "deploy-v1.2.3-prod",
Time: time.Now().UTC().Format(time.RFC3339),
Attrs: map[string]string{
"service.name": "api-service",
"service.version": "v1.2.3",
"deployment.environment": "production",
},
}
if err := createAnnotation(dsn, annotation); err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println("Annotation created successfully")
}
}

Python 示例

import requests
import json
from datetime import datetime
def create_annotation(dsn, annotation):
url = "https://api.uptrace.dev/api/v1/annotations"
headers = {
"Content-Type": "application/json",
"uptrace-dsn": dsn
}
response = requests.post(url, headers=headers, json=annotation)
response.raise_for_status()
return response.json()
# 使用示例
dsn = "https://your-token@api.uptrace.dev/your-project-id"
annotation = {
"name": "Deployed to production",
"description": "Deployed version **v1.2.3** to production.",
"color": "green",
"fingerprint": "deploy-v1.2.3-prod",
"time": datetime.utcnow().isoformat() + "Z",
"attrs": {
"service.name": "api-service",
"service.version": "v1.2.3",
"deployment.environment": "production"
}
}
try:
result = create_annotation(dsn, annotation)
print("Annotation created successfully:", result)
except requests.exceptions.RequestException as e:
print(f"Error creating annotation: {e}")

JavaScript/Node.js 示例

const https = require('https');
function createAnnotation(dsn, annotation) {
return new Promise((resolve, reject) => {
const data = JSON.stringify(annotation);
const options = {
hostname: 'api.uptrace.dev',
path: '/api/v1/annotations',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
'uptrace-dsn': dsn
}
};
const req = https.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(responseData));
} else {
reject(new Error(`Failed to create annotation: ${res.statusCode}`));
}
});
});
req.on('error', (error) => {
reject(error);
});
req.write(data);
req.end();
});
}
// 使用示例
const dsn = 'https://your-token@api.uptrace.dev/your-project-id';
const annotation = {
name: 'Deployed to production',
description: 'Deployed version **v1.2.3** to production.',
color: 'green',
fingerprint: 'deploy-v1.2.3-prod',
time: new Date().toISOString(),
attrs: {
'service.name': 'api-service',
'service.version': 'v1.2.3',
'deployment.environment': 'production'
}
};
createAnnotation(dsn, annotation)
.then(result => {
console.log('Annotation created successfully:', result);
})
.catch(error => {
console.error('Error creating annotation:', error);
});

使用场景

场景 1:CI/CD 集成

在 CI/CD 流水线中,在部署完成后自动创建注释:

#!/bin/bash
# deploy.sh
# 执行部署
./deploy.sh
# 部署成功后创建注释
curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Deployed $CI_COMMIT_SHORT_SHA\",
\"description\": \"Deployed commit [$CI_COMMIT_SHORT_SHA]($CI_PROJECT_URL/-/commit/$CI_COMMIT_SHA) to $DEPLOYMENT_ENV\",
\"color\": \"green\",
\"fingerprint\": \"deploy-$CI_COMMIT_SHORT_SHA-$DEPLOYMENT_ENV\",
\"attrs\": {
\"service.version\": \"$CI_COMMIT_SHORT_SHA\",
\"deployment.environment\": \"$DEPLOYMENT_ENV\",
\"ci.pipeline.id\": \"$CI_PIPELINE_ID\"
}
}"

场景 2:版本发布标记

在发布新版本时创建注释:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"v1.2.3 Release\",
\"description\": \"Released version **v1.2.3**\n\n**Highlights:**\n- Performance improvements\n- Bug fixes\n- New features\n\n[Release Notes](https://github.com/example/releases/tag/v1.2.3)\",
\"color\": \"blue\",
\"fingerprint\": \"release-v1.2.3\",
\"attrs\": {
\"release.version\": \"v1.2.3\",
\"release.type\": \"minor\"
}
}"

场景 3:故障事件标注

在发生故障时创建注释,便于后续分析:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Incident: Database Connection Pool Exhausted\",
\"description\": \"**Incident Report**\n\n- **Time**: $(date -u +%Y-%m-%dT%H:%M:%SZ)\n- **Severity**: High\n- **Impact**: Service degradation\n- **Root Cause**: Database connection pool exhausted\n- **Resolution**: Increased pool size\n\n[Incident Details](https://incident.example.com/INC-123)\",
\"color\": \"red\",
\"fingerprint\": \"incident-db-pool-$(date +%Y%m%d)\",
\"attrs\": {
\"incident.id\": \"INC-123\",
\"incident.severity\": \"high\",
\"incident.type\": \"database\"
}
}"

场景 4:数据库迁移标记

在执行数据库迁移时创建注释:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Database Migration: Add User Indexes\",
\"description\": \"Executed database migration to add indexes on user table.\n\n**Migration ID**: 20240115001\n**Duration**: 45 seconds\n**Status**: Success\",
\"color\": \"yellow\",
\"fingerprint\": \"migration-20240115001\",
\"attrs\": {
\"migration.id\": \"20240115001\",
\"migration.type\": \"schema\",
\"migration.status\": \"success\"
}
}"

场景 5:配置变更标记

在修改配置时创建注释:

curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "{
\"name\": \"Config Change: Increased Cache TTL\",
\"description\": \"Updated cache TTL from 5 minutes to 15 minutes.\n\n**Reason**: Reduce database load\n**Changed By**: admin@example.com\",
\"color\": \"orange\",
\"attrs\": {
\"config.change.type\": \"cache\",
\"config.change.reason\": \"performance\"
}
}"

注释管理

查看注释

在 Uptrace 平台中查看注释:

  1. 登录 Uptrace 平台:https://uptrace.inner.youdao.com/
  2. 选择项目
  3. 导航到 "Metrics" 页面
  4. 打开任意图表
  5. 注释会显示在 X 轴上,点击注释可以查看详细信息

注释过滤

在查看图表时,可以使用注释的属性进行过滤:

  • 按服务名称过滤:只显示特定服务的注释
  • 按环境过滤:只显示特定环境的注释
  • 按版本过滤:只显示特定版本的注释

注释去重

使用 fingerprint 字段可以防止创建重复的注释。如果多个注释具有相同的 fingerprint,Uptrace 只会保留第一个。

最佳实践:

  • 为每个唯一事件使用唯一的 fingerprint
  • 使用有意义的 fingerprint,例如:deploy-v1.2.3-prod、incident-db-pool-20240115
  • 避免使用随机字符串作为 fingerprint

最佳实践

1. 注释命名规范

建议使用统一的命名规范:

[事件类型]: [简短描述]

例如:

  • Deployment: v1.2.3 to production
  • Incident: Database connection pool exhausted
  • Migration: Add user indexes
  • Config Change: Increased cache TTL

2. 描述内容规范

描述应该包含:

  • 事件概述:简要说明发生了什么
  • 关键信息:版本号、时间、影响范围等
  • 相关链接:指向更多详细信息的链接(如发布说明、故障报告)

3. 属性使用建议

合理使用属性字段:

  • 必需属性:service.name、service.version、deployment.environment
  • 可选属性:根据事件类型添加相关属性
  • 避免过度使用:只添加有意义的属性,避免创建过多属性

4. 颜色使用建议

使用颜色来区分不同类型的事件:

  • 绿色:成功事件(部署、发布)
  • 红色:故障事件(故障、错误)
  • 黄色:警告事件(迁移、配置变更)
  • 蓝色:信息事件(版本发布、公告)
  • 橙色:重要事件(性能问题、容量警告)

5. 时间戳管理

  • 使用 UTC 时间:确保时间戳使用 UTC 时区
  • 精确到秒:对于需要精确时间的事件,使用秒级精度
  • 历史事件:使用 time 字段为历史事件创建注释

6. 与告警集成

将注释与告警系统集成:

  • 在告警触发时创建注释
  • 在告警恢复时创建注释
  • 使用注释标记故障的开始和结束时间

常见问题

1. 注释没有显示在图表上?

可能的原因:

  • 检查时间范围:确认注释的时间在图表的时间范围内
  • 检查属性过滤:如果图表使用了属性过滤,确认注释的属性匹配过滤条件
  • 检查 DSN:确认使用的 DSN 正确,且属于当前项目

2. 如何删除注释?

Uptrace 目前不提供删除注释的 API。如果需要删除注释,请联系管理员或通过 UI 操作。

3. 如何批量创建注释?

可以通过脚本循环调用 API 来批量创建注释:

#!/bin/bash
while IFS= read -r line; do
curl -X POST https://api.uptrace.dev/api/v1/annotations \
-H "uptrace-dsn: $UPTRACE_DSN" \
-H "Content-Type: application/json" \
-d "$line"
done < annotations.json

4. 注释支持哪些 Markdown 语法?

注释的描述字段支持标准 Markdown 语法:

  • 粗体:**text**
  • 斜体:*text*
  • 链接:[text](url)
  • 列表:- item 或 1. item
  • 代码:`code`
  • 代码块:```language\ncode\n```

5. 如何为历史事件创建注释?

使用 time 字段为历史事件创建注释:

{
"name": "Historical Event",
"time": "2024-01-01T00:00:00Z",
"description": "This is a historical event"
}

6. 注释会影响性能吗?

注释是轻量级的,不会影响性能。每个注释只存储少量元数据,不会影响指标查询或图表渲染性能。

下一步

参考资源

在Gitlab上编辑本文档