OpenTelemetry Instrumentation Extension by docker/mcp-gateway
npx skills add https://github.com/docker/mcp-gateway --skill 'OpenTelemetry Instrumentation Extension'根据 docs/telemetry/README.md 中记录的既定模式,自动为 MCP Gateway 中的新功能扩展 OpenTelemetry 仪表化。
在以下情况自动应用:
cmd/docker-mcp/ 添加了新的 CLI 命令pkg/ 中添加了包含操作的新包docs/telemetry/README.md 的 "开发指南" 部分pkg/telemetry/telemetry.go 以了解现有模式和指标广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
pkg/ 和 cmd/docker-mcp/ 中新增/更改的文件pkg/foo/ → 领域:foo)按此顺序执行:
pkg/telemetry/telemetry.go 添加指标docker logs otel-debug 输出pkg/telemetry/telemetry_test.go 添加测试docs/telemetry/README.md 添加指标/操作make test./docs/telemetry/testing/test-telemetry.sh遵循 docs/telemetry/README.md 中记录的项目指南:
DOCKER_MCP_TELEMETRY_DEBUG 后添加日志记录mcp.<领域>.<字段> 模式在建议更改之前,务必阅读这些文件:
docs/telemetry/README.md - 事实来源:
pkg/telemetry/telemetry.go - 了解:
pkg/telemetry/telemetry_test.go - 查看:
使用 cmd/docker-mcp/catalog/create.go 中的简单 defer 模式:
func OperationName(ctx context.Context, identifier string, ...) error {
telemetry.Init()
start := time.Now()
var success bool
defer func() {
duration := time.Since(start)
telemetry.Record<Domain>Operation(ctx, "operation_name", identifier,
float64(duration.Milliseconds()), success)
}()
// ... 操作逻辑 ...
// 可选:记录资源数量
telemetry.Record<Domain><Resources>(ctx, identifier, int64(count))
success = true
return nil
}
注意:如果标识符在执行过程中生成,defer 会捕获其最终值。
当需要为新领域(例如,新包 pkg/newdomain/)进行仪表化时:
pkg/telemetry/telemetry.go 中添加指标工具在 Init() 函数中,添加全局变量并创建指标工具:
var (
// ... 现有指标 ...
// 新领域指标
newdomainOperations metric.Int64Counter
newdomainOperationDuration metric.Float64Histogram
newdomainResources metric.Int64Gauge // 如果管理资源
)
func Init() {
// ... 现有初始化代码 ...
newdomainOperations, _ = meter.Int64Counter(
"mcp.newdomain.operations",
metric.WithDescription("New domain operations count"),
)
newdomainOperationDuration, _ = meter.Float64Histogram(
"mcp.newdomain.operation.duration",
metric.WithDescription("New domain operation duration in milliseconds"),
)
newdomainResources, _ = meter.Int64Gauge(
"mcp.newdomain.resources",
metric.WithDescription("Number of resources in new domain"),
)
}
pkg/telemetry/telemetry.go 中添加记录函数在 Init() 函数之后,添加记录函数:
func RecordNewdomainOperation(ctx context.Context, operation, identifier string, durationMs float64, success bool) {
if newdomainOperations == nil || newdomainOperationDuration == nil {
return
}
attrs := []attribute.KeyValue{
attribute.String("mcp.newdomain.operation", operation),
attribute.String("mcp.newdomain.id", identifier), // 或 .name, .ref 视情况而定
attribute.Bool("mcp.newdomain.success", success),
}
newdomainOperations.Add(ctx, 1, metric.WithAttributes(attrs...))
newdomainOperationDuration.Record(ctx, durationMs, metric.WithAttributes(attrs...))
}
// 可选:如果适用,添加资源计数函数
func RecordNewdomainResources(ctx context.Context, identifier string, count int64) {
if newdomainResources == nil {
return
}
attrs := []attribute.KeyValue{
attribute.String("mcp.newdomain.id", identifier),
}
newdomainResources.Record(ctx, count, metric.WithAttributes(attrs...))
}
pkg/telemetry/telemetry_test.go 中编写测试按照现有模式添加测试用例:
func TestRecordNewdomainOperation(t *testing.T) {
spanRecorder, metricReader := setupTestTelemetry(t)
Init()
ctx := context.Background()
// 测试成功操作
RecordNewdomainOperation(ctx, "create", "test-id", 123.45, true)
// 收集并验证指标
var rm metricdata.ResourceMetrics
err := metricReader.Collect(ctx, &rm)
require.NoError(t, err)
// 查找并验证计数器指标
foundCounter := false
foundHistogram := false
for _, sm := range rm.ScopeMetrics {
for _, m := range sm.Metrics {
if m.Name == "mcp.newdomain.operations" {
foundCounter = true
sum := m.Data.(metricdata.Sum[int64])
require.Len(t, sum.DataPoints, 1)
assert.Equal(t, int64(1), sum.DataPoints[0].Value)
// 验证属性
attrs := sum.DataPoints[0].Attributes
assert.Contains(t, attrs.ToSlice(), attribute.String("mcp.newdomain.operation", "create"))
assert.Contains(t, attrs.ToSlice(), attribute.String("mcp.newdomain.id", "test-id"))
assert.Contains(t, attrs.ToSlice(), attribute.Bool("mcp.newdomain.success", true))
}
if m.Name == "mcp.newdomain.operation.duration" {
foundHistogram = true
histogram := m.Data.(metricdata.Histogram[float64])
require.Len(t, histogram.DataPoints, 1)
assert.Equal(t, float64(123.45), histogram.DataPoints[0].Sum)
}
}
}
assert.True(t, foundCounter, "Counter metric not found")
assert.True(t, foundHistogram, "Histogram metric not found")
}
docs/telemetry/README.md 中的文档在适当位置为该领域添加新部分。遵循现有格式:
### 新领域操作
用于管理 [描述此领域功能] 的操作:
- **`mcp.newdomain.operations`** - 新领域操作(创建、更新、删除等)
- **`mcp.newdomain.operation.duration`** - 新领域操作的持续时间
- **`mcp.newdomain.resources`** - 显示新领域资源数量的仪表
#### 新领域属性
- **`mcp.newdomain.operation`** - 操作类型(创建、更新、删除等)
- **`mcp.newdomain.id`** - 资源的 ID
- **`mcp.newdomain.success`** - 指示操作成功的布尔值
进行更改后,验证遥测输出:
# 构建
make docker-mcp
# 启动 OTEL 收集器
docker run --rm -d --name otel-debug \
-p 4317:4317 -p 4318:4318 \
-v $(pwd)/docs/telemetry/testing/otel-collector-config.yaml:/config.yaml \
otel/opentelemetry-collector:latest --config=/config.yaml
# 启用遥测运行
export DOCKER_MCP_TELEMETRY_DEBUG=1
export DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
docker mcp [command]
# 检查收集器输出
docker logs otel-debug | grep "mcp.newdomain"
# 清理
docker stop otel-debug
在继续编写测试和文档之前,验证输出是否符合预期。
分析 git diff 时:
pkg/workingset/ → 领域:profilepkg/catalog_next/ → 领域:catalog_nextcmd/docker-mcp/server/ → 领域:serverpkg/telemetry/telemetry.go 中搜索 Record<Domain> 函数遵循此顺序:
docs/telemetry/README.md 阅读模式pkg/telemetry/telemetry.go 添加新指标(如果是新领域)docker logs otel-debug 验证 - 确认输出符合预期pkg/telemetry/telemetry_test.go 中编写测试docs/telemetry/README.mdmake test - 验证测试通过./docs/telemetry/testing/test-telemetry.sh - 最终验证每周安装
–
仓库
GitHub 星标
1.3K
首次出现
–
安全审计
Automatically extend OpenTelemetry instrumentation for new functionality in the MCP Gateway, following established patterns documented in docs/telemetry/README.md.
Automatically apply when:
cmd/docker-mcp/pkg/Read project telemetry standards :
docs/telemetry/README.md "Development Guidelines" sectionpkg/telemetry/telemetry.go to understand existing patterns and metricsIdentify scope using git diff:
pkg/ and cmd/docker-mcp/pkg/foo/ → domain: foo)Categorize findings :
Present suggestions to user:
Execute in this order:
pkg/telemetry/telemetry.godocker logs otel-debug outputpkg/telemetry/telemetry_test.godocs/telemetry/README.mdmake test./docs/telemetry/testing/test-telemetry.shFollow the project's documented guidelines from docs/telemetry/README.md:
DOCKER_MCP_TELEMETRY_DEBUGmcp.<domain>.<field> patternALWAYS read these files before suggesting changes:
docs/telemetry/README.md - Source of truth for:
pkg/telemetry/telemetry.go - Understand:
pkg/telemetry/telemetry_test.go - See:
Use the simple defer pattern from cmd/docker-mcp/catalog/create.go:
func OperationName(ctx context.Context, identifier string, ...) error {
telemetry.Init()
start := time.Now()
var success bool
defer func() {
duration := time.Since(start)
telemetry.Record<Domain>Operation(ctx, "operation_name", identifier,
float64(duration.Milliseconds()), success)
}()
// ... operation logic ...
// Optional: Record resource counts
telemetry.Record<Domain><Resources>(ctx, identifier, int64(count))
success = true
return nil
}
Note: If identifier is generated during execution, the defer captures its final value.
When instrumentation is needed for a new domain (e.g., new package pkg/newdomain/):
pkg/telemetry/telemetry.goIn the Init() function, add global variables and create metric instruments:
var (
// ... existing metrics ...
// New domain metrics
newdomainOperations metric.Int64Counter
newdomainOperationDuration metric.Float64Histogram
newdomainResources metric.Int64Gauge // If managing resources
)
func Init() {
// ... existing init code ...
newdomainOperations, _ = meter.Int64Counter(
"mcp.newdomain.operations",
metric.WithDescription("New domain operations count"),
)
newdomainOperationDuration, _ = meter.Float64Histogram(
"mcp.newdomain.operation.duration",
metric.WithDescription("New domain operation duration in milliseconds"),
)
newdomainResources, _ = meter.Int64Gauge(
"mcp.newdomain.resources",
metric.WithDescription("Number of resources in new domain"),
)
}
pkg/telemetry/telemetry.goAfter the Init() function, add recording functions:
func RecordNewdomainOperation(ctx context.Context, operation, identifier string, durationMs float64, success bool) {
if newdomainOperations == nil || newdomainOperationDuration == nil {
return
}
attrs := []attribute.KeyValue{
attribute.String("mcp.newdomain.operation", operation),
attribute.String("mcp.newdomain.id", identifier), // or .name, .ref as appropriate
attribute.Bool("mcp.newdomain.success", success),
}
newdomainOperations.Add(ctx, 1, metric.WithAttributes(attrs...))
newdomainOperationDuration.Record(ctx, durationMs, metric.WithAttributes(attrs...))
}
// Optional: Add resource counting function if applicable
func RecordNewdomainResources(ctx context.Context, identifier string, count int64) {
if newdomainResources == nil {
return
}
attrs := []attribute.KeyValue{
attribute.String("mcp.newdomain.id", identifier),
}
newdomainResources.Record(ctx, count, metric.WithAttributes(attrs...))
}
pkg/telemetry/telemetry_test.goAdd test cases following existing patterns:
func TestRecordNewdomainOperation(t *testing.T) {
spanRecorder, metricReader := setupTestTelemetry(t)
Init()
ctx := context.Background()
// Test successful operation
RecordNewdomainOperation(ctx, "create", "test-id", 123.45, true)
// Collect and verify metrics
var rm metricdata.ResourceMetrics
err := metricReader.Collect(ctx, &rm)
require.NoError(t, err)
// Find and verify the counter metric
foundCounter := false
foundHistogram := false
for _, sm := range rm.ScopeMetrics {
for _, m := range sm.Metrics {
if m.Name == "mcp.newdomain.operations" {
foundCounter = true
sum := m.Data.(metricdata.Sum[int64])
require.Len(t, sum.DataPoints, 1)
assert.Equal(t, int64(1), sum.DataPoints[0].Value)
// Verify attributes
attrs := sum.DataPoints[0].Attributes
assert.Contains(t, attrs.ToSlice(), attribute.String("mcp.newdomain.operation", "create"))
assert.Contains(t, attrs.ToSlice(), attribute.String("mcp.newdomain.id", "test-id"))
assert.Contains(t, attrs.ToSlice(), attribute.Bool("mcp.newdomain.success", true))
}
if m.Name == "mcp.newdomain.operation.duration" {
foundHistogram = true
histogram := m.Data.(metricdata.Histogram[float64])
require.Len(t, histogram.DataPoints, 1)
assert.Equal(t, float64(123.45), histogram.DataPoints[0].Sum)
}
}
}
assert.True(t, foundCounter, "Counter metric not found")
assert.True(t, foundHistogram, "Histogram metric not found")
}
docs/telemetry/README.mdAdd a new section for the domain in the appropriate location. Follow the existing format:
### New Domain Operations
Operations for managing [description of what this domain does]:
- **`mcp.newdomain.operations`** - New domain operations (create, update, delete, etc.)
- **`mcp.newdomain.operation.duration`** - Duration of new domain operations
- **`mcp.newdomain.resources`** - Gauge showing number of resources in new domain
#### New Domain Attributes
- **`mcp.newdomain.operation`** - Type of operation (create, update, delete, etc.)
- **`mcp.newdomain.id`** - ID of the resource
- **`mcp.newdomain.success`** - Boolean indicating operation success
After making changes, verify telemetry output:
# Build
make docker-mcp
# Start OTEL collector
docker run --rm -d --name otel-debug \
-p 4317:4317 -p 4318:4318 \
-v $(pwd)/docs/telemetry/testing/otel-collector-config.yaml:/config.yaml \
otel/opentelemetry-collector:latest --config=/config.yaml
# Run with telemetry enabled
export DOCKER_MCP_TELEMETRY_DEBUG=1
export DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
docker mcp [command]
# Check collector output
docker logs otel-debug | grep "mcp.newdomain"
# Cleanup
docker stop otel-debug
Verify the output matches expectations before proceeding to write tests and docs.
When analyzing git diff:
Look for operation verbs in function names:
Look for state changes :
Infer domain from file path:
pkg/workingset/ → domain: profilepkg/catalog_next/ → domain: catalog_nextcmd/docker-mcp/server/ → domain: serverFollow this sequence:
docs/telemetry/README.mdpkg/telemetry/telemetry.go (if new domain)docker logs otel-debug - confirm output matches expectationspkg/telemetry/telemetry_test.godocs/telemetry/README.md with new metricsmake test - verify tests pass./docs/telemetry/testing/test-telemetry.sh - final verificationWeekly Installs
–
Repository
GitHub Stars
1.3K
First Seen
–
Security Audits
Check if telemetry exists :
pkg/telemetry/telemetry.go for Record<Domain> functions