- ClickStack
- 数据摄取
- SDKS
- Golang
Golang
ClickStack 使用 OpenTelemetry 标准来收集遥测数据(日志和追踪)。通过自动插桩可以自动生成追踪数据,因此无需手动插桩也能从追踪中获得价值。
本指南集成:
| ✅ 日志 | ✅ 指标 | ✅ 链路追踪 |
快速开始
安装 OpenTelemetry 插桩包
要安装 OpenTelemetry 和 HyperDX 的 Go 包,请使用以下命令。建议查看当前可用的插桩包,并安装所需的包,以确保 Trace 信息能够被正确关联。
go get -u go.opentelemetry.io/otel
go get -u github.com/hyperdxio/otel-config-go
go get -u github.com/hyperdxio/opentelemetry-go
go get -u github.com/hyperdxio/opentelemetry-logs-go
原生 HTTP 服务器示例(net/http)
在本示例中,我们将使用 net/http/otelhttp 包。
go get -u go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp
参考代码中的注释部分,了解如何为 Go 应用添加埋点(instrumentation)。
package main
import (
"context"
"io"
"log"
"net/http"
"os"
"github.com/hyperdxio/opentelemetry-go/otelzap"
"github.com/hyperdxio/opentelemetry-logs-go/exporters/otlp/otlplogs"
"github.com/hyperdxio/otel-config-go/otelconfig"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
sdk "github.com/hyperdxio/opentelemetry-logs-go/sdk/logs"
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
"go.opentelemetry.io/otel/sdk/resource"
)
// 为所有日志配置通用属性
func newResource() *resource.Resource {
hostName, _ := os.Hostname()
return resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceVersion("1.0.0"),
semconv.HostName(hostName),
)
}
// 将 trace ID 附加到日志
func WithTraceMetadata(ctx context.Context, logger *zap.Logger) *zap.Logger {
spanContext := trace.SpanContextFromContext(ctx)
if !spanContext.IsValid() {
// ctx 不包含有效的 span。
// 没有 trace 元数据可添加。
return logger
}
return logger.With(
zap.String("trace_id", spanContext.TraceID().String()),
zap.String("span_id", spanContext.SpanID().String()),
)
}
func main() {
// 初始化 OTel 配置并在整个应用中使用
otelShutdown, err := otelconfig.ConfigureOpenTelemetry()
if err != nil {
log.Fatalf("设置 OTel SDK 时出错 - %e", err)
}
defer otelShutdown()
ctx := context.Background()
// 配置 OpenTelemetry logger provider
logExporter, _ := otlplogs.NewExporter(ctx)
loggerProvider := sdk.NewLoggerProvider(
sdk.WithBatcher(logExporter),
)
// 优雅关闭 logger 以在程序结束前刷新累积的信号
defer loggerProvider.Shutdown(ctx)
// 使用 OpenTelemetry zap core 创建新 logger 并全局设置
logger := zap.New(otelzap.NewOtelCore(loggerProvider))
zap.ReplaceGlobals(logger)
logger.Warn("hello world", zap.String("foo", "bar"))
http.Handle("/", otelhttp.NewHandler(wrapHandler(logger, ExampleHandler), "example-service"))
port := os.Getenv("PORT")
if port == "" {
port = "7777"
}
logger.Info("** 服务已在端口 " + port + " 启动 **")
if err := http.ListenAndServe(":"+port, nil); err != nil {
logger.Fatal(err.Error())
}
}
// 使用此函数包装所有 handler 以向 logger 添加 trace 元数据
func wrapHandler(logger *zap.Logger, handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := WithTraceMetadata(r.Context(), logger)
logger.Info("收到请求", zap.String("url", r.URL.Path), zap.String("method", r.Method))
handler(w, r)
logger.Info("请求完成", zap.String("path", r.URL.Path), zap.String("method", r.Method))
}
}
func ExampleHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
io.WriteString(w, `{"status":"ok"}`)
}
Gin 应用程序示例
在本示例中,我们将使用 gin-gonic/gin。
go get -u go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin
请参考注释部分,了解如何为你的 Go 应用程序添加埋点(instrumentation)。
package main
import (
"context"
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/hyperdxio/opentelemetry-go/otelzap"
"github.com/hyperdxio/opentelemetry-logs-go/exporters/otlp/otlplogs"
sdk "github.com/hyperdxio/opentelemetry-logs-go/sdk/logs"
"github.com/hyperdxio/otel-config-go/otelconfig"
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
"go.opentelemetry.io/otel/trace"
"go.uber.org/zap"
)
// 将 trace ID 附加到日志
func WithTraceMetadata(ctx context.Context, logger *zap.Logger) *zap.Logger {
spanContext := trace.SpanContextFromContext(ctx)
if !spanContext.IsValid() {
// ctx 不包含有效的 span。
// 无需添加 trace 元数据。
return logger
}
return logger.With(
zap.String("trace_id", spanContext.TraceID().String()),
zap.String("span_id", spanContext.SpanID().String()),
)
}
func main() {
// 初始化 OTel 配置并在整个应用程序中使用
otelShutdown, err := otelconfig.ConfigureOpenTelemetry()
if err != nil {
log.Fatalf("设置 OTel SDK 出错 - %e", err)
}
defer otelShutdown()
ctx := context.Background()
// 配置 OpenTelemetry 日志提供器
logExporter, _ := otlplogs.NewExporter(ctx)
loggerProvider := sdk.NewLoggerProvider(
sdk.WithBatcher(logExporter),
)
// 优雅关闭日志记录器以在程序结束前刷新累积的信号
defer loggerProvider.Shutdown(ctx)
// 使用 OpenTelemetry zap 核心创建新日志记录器并全局设置
logger := zap.New(otelzap.NewOtelCore(loggerProvider))
zap.ReplaceGlobals(logger)
// 创建新 Gin 路由器
router := gin.Default()
router.Use(otelgin.Middleware("service-name"))
// 定义响应根 URL GET 请求的路由
router.GET("/", func(c *gin.Context) {
_logger := WithTraceMetadata(c.Request.Context(), logger)
_logger.Info("Hello World!")
c.String(http.StatusOK, "Hello World!")
})
// 在端口 7777 运行服务器
router.Run(":7777")
}
配置环境变量
接下来需要在 shell 中配置下列环境变量,以将遥测数据发送到 ClickStack:
export OTEL_EXPORTER_OTLP_ENDPOINT=https://localhost:4318 \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_SERVICE_NAME='<NAME_OF_YOUR_APP_OR_SERVICE>' \
OTEL_EXPORTER_OTLP_HEADERS='authorization=<YOUR_INGESTION_API_KEY>'
环境变量 OTEL_EXPORTER_OTLP_HEADERS 包含可通过 HyperDX 应用的 Team Settings → API Keys 获取的 API Key。