| name | selfmonitor |
| description | 自监控指标、告警代码标准 |
自监控代码标准
你是一个自监控代码质量专家,负责确保LoongCollector中所有代码正确使用自监控功能。你的职责是检查指标使用、告警使用、代码风格和实现逻辑的正确性。
指标命名规范
命名格式
变量名基本格式: {模块}_{指标内容描述}_{单位}(全部大写)
变量内容基本格式: {指标内容描述}_{单位}(全部小写)
例如:
const string METRIC_RUNNER_FLUSHER_IN_RAW_SIZE_BYTES = "in_raw_size_bytes";
模块前缀分类
agent_: 进程级指标,描述整个Agent的状态
pipeline_: Pipeline级指标,描述数据流水线的状态
plugin_: 插件级指标,描述具体插件的状态
component_: 组件级指标,描述内部组件的状态
runner_: Runner级指标,描述运行器的状态
单位分类规范
根据指标类型和用途,使用以下标准单位:
计数类指标
_total: 累计总数(默认单位,无单位时使用)
- 示例:
input_records_total, send_success_total, error_count_total
大小类指标
_bytes: 字节数
- 示例:
input_size_bytes, memory_used_bytes, file_size_bytes
_mb: 兆字节(内存使用等)
- 示例:
agent_memory_used_mb, go_memory_used_mb
时间类指标
_ms: 毫秒(处理时间、延迟等)
- 示例:
process_time_ms, send_delay_ms, read_delay_ms
_s: 秒(长时间间隔)
- 示例:
uptime_s, last_run_time_s
比率类指标
_percent: 百分比
- 示例:
cpu_usage_percent, memory_usage_percent
_ps: 每秒(速率)
- 示例:
send_bytes_ps, process_lines_ps
状态类指标
_flag: 标志位(0或1)
- 示例:
enabled_flag, valid_flag
_state: 状态值
- 示例:
register_state, connection_state
指标内容描述规范
- 使用下划线分隔的英文描述
- 动词使用过去分词形式:
processed, sent, failed
- 名词使用复数形式:
events, records, errors
- 避免缩写,使用完整单词
正确示例:
METRIC_AGENT_CPU_PERCENT
METRIC_AGENT_MEMORY_USED_MB
METRIC_PLUGIN_IN_EVENTS_TOTAL
METRIC_PLUGIN_OUT_SIZE_BYTES
METRIC_PIPELINE_PROCESSORS_TOTAL_PROCESS_TIME_MS
METRIC_RUNNER_LAST_RUN_TIME
METRIC_COMPONENT_QUEUE_SIZE
错误示例:
CPU_PERCENT
METRIC_AGENT_MEMORY_USED_KB
METRIC_PLUGIN_DATA
METRIC_AGENT_MEM_MB
Label命名规范
Label Key格式: METRIC_LABEL_KEY_{描述}
常用Label Key:
METRIC_LABEL_KEY_PROJECT
METRIC_LABEL_KEY_LOGSTORE
METRIC_LABEL_KEY_PIPELINE_NAME
METRIC_LABEL_KEY_PLUGIN_TYPE
METRIC_LABEL_KEY_PLUGIN_ID
METRIC_LABEL_KEY_FILE_NAME
METRIC_LABEL_KEY_FILE_DEV
METRIC_LABEL_KEY_FILE_INODE
METRIC_LABEL_KEY_REGION
METRIC_LABEL_KEY_RUNNER_NAME
告警等级使用规范
告警等级定义
根据PR #2319的设计,告警等级分为3个级别:
| 等级 | 严重程度 | 说明 | 典型场景 |
|---|
| 1 | warning | 单点报错,不影响整体流程 | 数据解析失败;单次采集/发送失败 |
| 2 | error | 对主要流程有影响,如果不优化处理可能导致风险 | 队列繁忙;监控超限;未成功的初始化操作 |
| 3 | critical | 严重影响,会导致:采集配置/重要模块不可用;对Agent稳定性造成影响;会导致客户资损 | 配置加载失败;未成功的模块初始化操作;丢弃数据;crash |
C++告警使用规范
正确使用方式:
AlarmManager::GetInstance()->SendAlarmWarning(LOGTAIL_CONFIG_ALARM, "配置解析失败");
AlarmManager::GetInstance()->SendAlarmError(PROCESS_QUEUE_BUSY_ALARM, "处理队列繁忙");
AlarmManager::GetInstance()->SendAlarmCritical(CATEGORY_CONFIG_ALARM, "配置加载失败");
错误使用方式:
AlarmManager::GetInstance()->SendAlarm(LOGTAIL_CONFIG_ALARM, "配置解析失败");
Go告警使用规范
正确使用方式:
logger.Warning(ctx, selfmonitor.CategoryConfigAlarm, "配置解析失败")
logger.Error(ctx, selfmonitor.ProcessQueueBusyAlarm, "处理队列繁忙")
logger.Critical(ctx, selfmonitor.CategoryConfigAlarm, "配置加载失败")
错误使用方式:
logger.Warning(ctx, "UNKNOWN_ALARM", "未知告警")
新增指标操作指南
C++新增指标步骤
-
定义指标常量:
- 在
core/monitor/metric_constants/MetricConstants.h 中添加指标常量
- 在对应的
.cpp 文件中实现常量值
-
创建MetricsRecordRef:
MetricsRecordRef mMetricsRecordRef;
void Plugin::Init() {
MetricLabelsPtr labels = std::make_shared<MetricLabels>();
labels->emplace_back(METRIC_LABEL_KEY_PROJECT, mProject);
labels->emplace_back(METRIC_LABEL_KEY_PLUGIN_TYPE, mPluginType);
WriteMetrics::GetInstance()->PrepareMetricsRecordRef(
mMetricsRecordRef,
std::move(labels),
nullptr
);
}
-
创建指标对象:
CounterPtr mCounterPtr;
IntGaugePtr mGaugePtr;
void Plugin::Init() {
mCounterPtr = mMetricsRecordRef.CreateCounter(METRIC_PLUGIN_IN_EVENTS_TOTAL);
mGaugePtr = mMetricsRecordRef.CreateIntGauge(METRIC_PLUGIN_QUEUE_SIZE);
mMetricsRecordRef.Commit();
}
-
更新指标值:
void Plugin::ProcessData() {
(mMetricsRecordRef.()) {
(mCounterPtr, value);
(mGaugePtr, value);
(mGaugePtr, delta);
}
}
重要注意事项:
MetricsRecordRef必须在commit前创建所有指标对象
- commit后不能再调用
CreateCounter、CreateIntGauge等方法
- 使用
IsCommitted()检查状态,避免在已提交后创建指标
- 若某个Gauge类型的指标对应的参数的默认值非0,需要在Init的时候先将值Set一次
Go新增指标步骤
-
定义指标常量:
- 在
pkg/selfmonitor/metrics_constants_*.go 中添加指标常量
const (
MetricPluginInEventsTotal = "in_events_total"
MetricPluginQueueSize = "queue_size"
)
-
注册指标:
type Plugin struct {
pipeline.PluginContext
metricCounter selfmonitor.CounterMetric
metricGauge selfmonitor.GaugeMetric
}
func (p *Plugin) InitMetricRecord(pluginMeta *pipeline.PluginMeta) {
labels := pipeline.GetPluginCommonLabels(p.Config.Context, pluginMeta)
p.MetricRecord = p.Config.Context.RegisterMetricRecord(labels)
p.metricCounter = selfmonitor.NewCounterMetricAndRegister(p.MetricRecord, selfmonitor.MetricPluginInEventsTotal)
p.metricGauge = selfmonitor.NewGaugeMetricAndRegister(p.MetricRecord, selfmonitor.MetricPluginQueueSize)
}
-
更新指标值:
func (p *Plugin) ProcessData() {
if p.metricCounter != nil {
p.metricCounter.Add(1)
}
if p.metricGauge != nil {
p.metricGauge.Set(queueSize)
}
}
重要注意事项:
- 使用
InitMetricRecord方法初始化指标
- 通过
NewCounterMetricAndRegister和NewGaugeMetricAndRegister创建并注册指标
- 更新指标值前检查对象是否为nil
- 指标会自动上报,无需手动提交
新增告警类型操作指南
C++新增告警类型步骤
-
在 core/monitor/AlarmManager.h 中添加告警类型:
enum AlarmType {
NEW_ALARM_TYPE = 70,
ALL_LOGTAIL_ALARM_NUM = 71
};
-
在告警消息类型映射中添加:
AlarmManager::AlarmManager() {
mMessageType.push_back("NEW_ALARM_TYPE");
}
-
使用告警:
void SomeFunction() {
AlarmManager::GetInstance()->SendAlarmWarning(
NEW_ALARM_TYPE,
"具体错误信息: " + errorDetails
);
AlarmManager::GetInstance()->SendAlarmError(
NEW_ALARM_TYPE,
"严重错误信息"
);
}
重要注意事项:
- 告警类型枚举值必须连续,不能跳跃
- 更新
ALL_LOGTAIL_ALARM_NUM为新的总数
- 在
mMessageType向量中添加对应的字符串
- 使用等级化接口,避免使用旧的
SendAlarm方法
Go新增告警类型步骤
-
在 pkg/selfmonitor/alarm_constants.go 中添加告警类型:
const (
NewAlarmType AlarmType = "NEW_ALARM_TYPE"
)
-
使用告警:
func (p *Plugin) ProcessData() error {
if err := p.doSomething(); err != nil {
logger.Warning(ctx, selfmonitor.NewAlarmType,
fmt.Sprintf("处理数据失败: %v", err))
return err
}
if p.isCriticalError() {
logger.Critical(ctx, selfmonitor.NewAlarmType,
"严重错误,需要立即处理")
}
return nil
}
重要注意事项:
- 告警类型字符串必须与C++中的枚举名称一致
- 使用等级化接口:
Warning、Error、Critical
- 告警消息应该包含具体的错误信息
- 避免在循环中频繁发送相同告警
代码风格规范
C++代码风格
-
命名规范:
- 类名使用PascalCase:
AlarmManager, MetricRecord
- 函数名使用camelCase:
SendAlarmWarning, GetInstance
- 常量使用SCREAMING_SNAKE_CASE:
METRIC_AGENT_CPU
- 成员变量使用m前缀:
mAlarmBufferMutex, mAllAlarmMap
-
代码结构:
- 头文件声明与实现分离
- 使用namespace logtail包装
- 适当的const和constexpr使用
Go代码风格
-
命名规范:
- 包名使用小写:
selfmonitor
- 类型名使用PascalCase:
AlarmType, AlarmLevel
- 函数名使用camelCase:
Record, SerializeToPb
- 常量使用SCREAMING_SNAKE_CASE:
AlarmLevelWarning
-
代码结构:
- 适当的错误处理
- 使用sync.Mutex保护并发访问
- 清晰的注释和文档
指标使用最佳实践
指标创建最佳实践
-
在合适的生命周期创建指标:
C++示例:
class Plugin {
private:
MetricsRecordRef mMetricsRecordRef;
CounterPtr mProcessedCounter;
IntGaugePtr mQueueSizeGauge;
public:
bool Init() {
MetricLabelsPtr labels = std::make_shared<MetricLabels>();
labels->emplace_back(METRIC_LABEL_KEY_PLUGIN_TYPE, "input_file");
WriteMetrics::GetInstance()->PrepareMetricsRecordRef(
mMetricsRecordRef, std::move(labels), nullptr);
mProcessedCounter = mMetricsRecordRef.CreateCounter(METRIC_PLUGIN_PROCESSED_TOTAL);
mQueueSizeGauge = mMetricsRecordRef.CreateIntGauge(METRIC_PLUGIN_QUEUE_SIZE);
mMetricsRecordRef.Commit();
return true;
}
};
Go示例:
type Plugin struct {
pipeline.PluginContext
processedCounter selfmonitor.CounterMetric
queueSizeGauge selfmonitor.GaugeMetric
}
func (p *Plugin) InitMetricRecord(pluginMeta *pipeline.PluginMeta) {
labels := pipeline.GetPluginCommonLabels(p.Config.Context, pluginMeta)
p.MetricRecord = p.Config.Context.RegisterMetricRecord(labels)
p.processedCounter = selfmonitor.NewCounterMetricAndRegister(p.MetricRecord, selfmonitor.MetricPluginProcessedTotal)
p.queueSizeGauge = selfmonitor.NewGaugeMetricAndRegister(p.MetricRecord, selfmonitor.MetricPluginQueueSize)
}
告警使用最佳实践
-
选择合适的告警等级:
void ProcessData() {
if (parseError) {
AlarmManager::GetInstance()->SendAlarmWarning(
PARSE_LOG_FAIL_ALARM,
"单行解析失败: " + errorLine
);
}
if (queueFull) {
AlarmManager::GetInstance()->SendAlarmError(
PROCESS_QUEUE_BUSY_ALARM,
"处理队列已满,当前大小: " + std::to_string(queueSize)
);
}
if (configLoadFailed) {
AlarmManager::GetInstance()->SendAlarmCritical(
CATEGORY_CONFIG_ALARM,
"采集配置加载失败: " + configError
);
}
}
-
提供有意义的告警消息:
void HandleFileError(const std::string& filePath, int errorCode) {
std::string message = "文件读取失败: " + filePath +
", 错误码: " + std::to_string(errorCode) +
", 建议检查文件权限和路径";
AlarmManager::GetInstance()->SendAlarmError(
OPEN_LOGFILE_FAIL_ALARM,
message
);
}
void HandleFileErrorWrong(const std::string& filePath) {
AlarmManager::()->(
OPEN_LOGFILE_FAIL_ALARM,
);
}
检查清单
在提交涉及自监控的代码前,请确保:
-
指标命名:
-
告警使用:
-
代码实现:
-
性能考虑:
-
测试验证: