diff --git a/README.md b/README.md index d4979434d..2de5ac13e 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,11 @@ A collection of runnable Dubbo-go examples covering configuration, registries, o * `java_interop`: Demonstrates interoperability between Java and Go Dubbo implementations. * `llm`: Example of integrating Large Language Models (LLMs) with Dubbo-go. * `logger`: Logging examples for Dubbo-go applications. + * `logger/default`: Print to console by default. + * `logger/level`: Set log isolation level. + * `logger/rolling`: Output to file. + * `logger/custom`: Custom logger. + * `logger/trace-integration`: Integrate OpenTelemetry trace information, automatically injecting trace_id, span_id and other information into logs. * `metrics`: Shows how to collect and expose metrics from Dubbo-go services, supporting both Prometheus Push and Pull modes. Also includes the `pgw-cleaner` tool for cleaning zombie metrics in Push mode. * `mesh`: Proxy-based service mesh example showing how to deploy Dubbo-go services with Envoy on Kubernetes. * `online_boutique`: Microservices “online boutique” demo built with Dubbo-go. diff --git a/README_CN.md b/README_CN.md index f54f82869..db342b0fb 100644 --- a/README_CN.md +++ b/README_CN.md @@ -29,6 +29,11 @@ * `java_interop`:展示 Java 与 Go Dubbo 实现之间的互操作能力。 * `llm`:将大模型(LLM)集成到 Dubbo-go 中的示例。 * `logger`:Dubbo-go 应用的日志使用示例。 + * `logger/default`:默认打印到控制台。 + * `logger/level`:设置日志隔离级别。 + * `logger/rolling`:输出到文件。 + * `logger/custom`:自定义 logger。 + * `logger/trace-integration`:集成 OpenTelemetry trace 信息,自动将 trace_id、span_id 等信息注入日志。 * `metrics`:展示如何采集并暴露 Dubbo-go 服务的指标,支持 Prometheus Push 和 Pull 两种模式;同时包含用于清理 Push 模式僵尸指标的 `pgw-cleaner` 工具。 * `mesh`:基于代理的服务网格示例,展示如何在 Kubernetes 上结合 Envoy 部署 Dubbo-go 服务。 * `online_boutique`:基于 Dubbo-go 构建的微服务 “在线商城” 演示项目。 diff --git a/logger/README.md b/logger/README.md index 5c5ced323..4373170c7 100644 --- a/logger/README.md +++ b/logger/README.md @@ -8,6 +8,7 @@ The samples demonstrate how to configure dubbo-go logger using lumberjack * level: set the isolation level of the log * rolling: output to file * custom: set custom logger +* trace-integration: integrate OpenTelemetry trace information #### print to the console by default @@ -26,6 +27,9 @@ zap log format and level settings max-age: 3 max-backups: 5 compress: false + trace-integration: + enabled: false + record-error-to-span: false ``` #### set isolation level @@ -74,3 +78,66 @@ Then call SetLogger method to set logger ```go logger.SetLogger(&customLogger{}) ``` + +#### Integrate OpenTelemetry trace information + +logger supports OpenTelemetry trace integration, automatically injecting trace information into logs. + +##### Method 1: New API (Recommended) + +```go +ins, err := dubbo.NewInstance( + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), + dubbo.WithLogger( + log.WithZap(), + log.WithTraceIntegration(true), + log.WithRecordErrorToSpan(true), + ), +) +``` + +##### Method 2: Old API + +```go +loggerConfig := config.NewLoggerConfigBuilder(). + SetDriver("zap"). + SetTraceIntegrationEnabled(true). + SetRecordErrorToSpan(true). + Build() +loggerConfig.Init() +``` + +##### Using CtxLogger + +```go +import ( + "context" +) + +import ( + gostLogger "github.com/dubbogo/gost/log/logger" + "dubbo.apache.org/dubbo-go/v3/logger" +) + +// Get CtxLogger +rawLogger := gostLogger.GetLogger() +ctxLog := rawLogger.(logger.CtxLogger) + +// Create a context (e.g., from an incoming request or with trace information) +ctx := context.Background() + +// Log with context +ctxLog.CtxInfo(ctx, "hello dubbogo this is info log") +ctxLog.CtxDebug(ctx, "hello dubbogo this is debug log") +ctxLog.CtxWarn(ctx, "hello dubbogo this is warn log") +ctxLog.CtxError(ctx, "hello dubbogo this is error log") + +// Formatted logging +ctxLog.CtxInfof(ctx, "user: %s", "alice") +ctxLog.CtxDebugf(ctx, "value: %d", 42) +ctxLog.CtxWarnf(ctx, "latency: %dms", 150) +ctxLog.CtxErrorf(ctx, "failed: %v", err) +``` diff --git a/logger/README_zh.md b/logger/README_zh.md index 02b276d53..ce945eabd 100644 --- a/logger/README_zh.md +++ b/logger/README_zh.md @@ -8,6 +8,7 @@ * level: 设置日志的隔离级别 * rolling: 输出到文件 * custom: 自定义 logger +* trace-integration: 集成 OpenTelemetry trace 信息 #### 默认配置 @@ -26,6 +27,9 @@ zap 日志格式和级别设置 max-age: 3 max-backups: 5 compress: false + trace-integration: + enabled: false + record-error-to-span: false ``` #### 设置隔离级别 @@ -68,4 +72,67 @@ type Logger interface { 然后调用 SetLogger 方法设置 logger ```go logger.SetLogger(&customLogger{}) -``` \ No newline at end of file +``` + +#### 集成 OpenTelemetry trace 信息 + +logger 支持 OpenTelemetry trace 集成,自动将 trace 信息注入日志。 + +##### 方式1:New API(推荐) + +```go +ins, err := dubbo.NewInstance( + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), + dubbo.WithLogger( + log.WithZap(), + log.WithTraceIntegration(true), + log.WithRecordErrorToSpan(true), + ), +) +``` + +##### 方式2:Old API + +```go +loggerConfig := config.NewLoggerConfigBuilder(). + SetDriver("zap"). + SetTraceIntegrationEnabled(true). + SetRecordErrorToSpan(true). + Build() +loggerConfig.Init() +``` + +##### 使用 CtxLogger 记录日志 + +```go +import ( + "context" +) + +import ( + gostLogger "github.com/dubbogo/gost/log/logger" + "dubbo.apache.org/dubbo-go/v3/logger" +) + +// 获取 CtxLogger +rawLogger := gostLogger.GetLogger() +ctxLog := rawLogger.(logger.CtxLogger) + +// 创建 context(例如从请求中获取,或包含 trace 信息) +ctx := context.Background() + +// 使用 context 记录日志 +ctxLog.CtxInfo(ctx, "hello dubbogo this is info log") +ctxLog.CtxDebug(ctx, "hello dubbogo this is debug log") +ctxLog.CtxWarn(ctx, "hello dubbogo this is warn log") +ctxLog.CtxError(ctx, "hello dubbogo this is error log") + +// 格式化日志 +ctxLog.CtxInfof(ctx, "user: %s", "alice") +ctxLog.CtxDebugf(ctx, "value: %d", 42) +ctxLog.CtxWarnf(ctx, "latency: %dms", 150) +ctxLog.CtxErrorf(ctx, "failed: %v", err) +``` diff --git a/logger/trace-integration/cmd/main.go b/logger/trace-integration/cmd/main.go new file mode 100644 index 000000000..6dd470f0c --- /dev/null +++ b/logger/trace-integration/cmd/main.go @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "context" + "time" +) + +import ( + "dubbo.apache.org/dubbo-go/v3" + _ "dubbo.apache.org/dubbo-go/v3/imports" + log "dubbo.apache.org/dubbo-go/v3/logger" + "dubbo.apache.org/dubbo-go/v3/protocol" + + "github.com/dubbogo/gost/log/logger" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/sdk/trace" +) + +func main() { + ins, err := dubbo.NewInstance( + dubbo.WithProtocol( + protocol.WithTriple(), + protocol.WithPort(20000), + ), + dubbo.WithLogger( + log.WithZap(), + log.WithLevel("debug"), + log.WithTraceIntegration(true), + log.WithRecordErrorToSpan(true), + ), + ) + if err != nil { + panic(err) + } + + server, err := ins.NewServer() + if err != nil { + panic(err) + } + go server.Serve() + + // setup OpenTelemetry tracer + tp := trace.NewTracerProvider() + defer func() { + if err := tp.Shutdown(context.Background()); err != nil { + panic(err) + } + }() + otel.SetTracerProvider(tp) + tracer := tp.Tracer("demo") + + // run for 3 seconds + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + defer cancel() + + // create trace span from the timeout context + traceCtx, span := tracer.Start(ctx, "demo-operation") + defer span.End() + + // get CtxLogger + rawLogger := logger.GetLogger() + ctxLog := rawLogger.(log.CtxLogger) + + for { + select { + case <-ctx.Done(): + return + default: + // log with trace context (automatically includes trace_id, span_id) + ctxLog.CtxInfo(traceCtx, "hello dubbogo this is info log") + ctxLog.CtxDebug(traceCtx, "hello dubbogo this is debug log") + ctxLog.CtxWarn(traceCtx, "hello dubbogo this is warn log") + ctxLog.CtxError(traceCtx, "hello dubbogo this is error log") + time.Sleep(time.Second * 1) + } + } +}