elasticapm

package module
v0.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2026 License: MIT Imports: 13 Imported by: 1

README

GitHub Workflow Status (branch) GoDoc Coverage Status Supported Go Versions GitHub Release Go Report Card

elasticapm

Simple and elegant wrapping of Elastic APM (Application Performance Monitoring) in Go, based on go.elastic.co/apm/v2.


CHINESE README

中文说明

Main Features

🎯 Simple APM Setup: Config struct-based initialization with less boilerplate code ⚡ Zap Logging Integration: Built-in Zap logging support with APM context tracking 🔄 gRPC Distributed Tracing: W3C trace headers propagation across gRPC boundaries 🌍 Environment Variables: Automatic environment setup with override controls 📋 Version Matching: Ensures v2 usage preventing v1/v2 mixing pitfalls

Installation

go get github.com/yylego/elasticapm
Requirements
  • Go 1.23.0 and above
  • Elastic APM Server v2.x

Usage

Basic APM with Transactions and Spans

This example shows complete APM setup with transaction tracking and span instrumentation:

package main

import (
	"time"

	"github.com/yylego/elasticapm"
	"github.com/yylego/must"
	"github.com/yylego/zaplog"
	"go.elastic.co/apm/v2"
	"go.uber.org/zap"
)

func main() {
	// Initialize zap logging first
	zaplog.SUG.Info("Starting APM demo")

	// Configure APM settings
	cfg := &elasticapm.Config{
		Environment:    "development",
		ServerUrl:      "http://localhost:8200",
		ServiceName:    "demo-basic-service",
		ServiceVersion: "1.0.0",
		SkipShortSpans: false, // Capture all spans
	}

	// Initialize APM
	must.Done(elasticapm.Initialize(cfg))
	defer elasticapm.Close()

	zaplog.SUG.Info("APM initialized", zap.String("version", elasticapm.GetApmAgentVersion()))

	// Verify version compatibility
	if elasticapm.CheckApmAgentVersion(apm.AgentVersion) {
		zaplog.SUG.Info("APM version check passed")
	}

	// Start a transaction
	txn := apm.DefaultTracer().StartTransaction("demo-operation", "custom")
	defer txn.End()

	zaplog.SUG.Info("Transaction started", zap.String("transaction_id", txn.TraceContext().Trace.String()))

	// Simulate some work with a span
	span := txn.StartSpan("process-data", "internal", nil)
	processData()
	span.End()

	// Second span simulating database operation
	dbSpan := txn.StartSpan("database-query", "db.query", nil)
	dbSpan.Context.SetDatabase(apm.DatabaseSpanContext{
		Statement: "SELECT * FROM users WHERE id = ?",
		Type:      "sql",
	})
	simulateDatabaseOperation()
	dbSpan.End()

	zaplog.SUG.Info("Demo completed")
}

func processData() {
	// Simulate data processing
	time.Sleep(100 * time.Millisecond)
	zaplog.SUG.Debug("Data processed")
}

func simulateDatabaseOperation() {
	// Simulate database operation
	time.Sleep(50 * time.Millisecond)
	zaplog.SUG.Debug("Database operation executed")
}

⬆️ Source: Source

gRPC Distributed Tracing

This example demonstrates W3C trace headers propagation across gRPC service boundaries:

package main

import (
	"context"
	"time"

	"github.com/yylego/elasticapm"
	"github.com/yylego/must"
	"github.com/yylego/zaplog"
	"go.uber.org/zap"
)

func main() {
	// Initialize zap logging
	zaplog.SUG.Info("Starting gRPC APM demo")

	// Configure APM
	cfg := &elasticapm.Config{
		Environment:    "development",
		ServerUrl:      "http://localhost:8200",
		ServiceName:    "demo-grpc-client",
		ServiceVersion: "1.0.0",
	}

	// Initialize APM
	must.Done(elasticapm.Initialize(cfg))
	defer elasticapm.Close()

	zaplog.SUG.Info("APM initialized for gRPC demo")

	// Simulate gRPC client call with distributed tracing
	ctx := context.Background()
	callRemoteService(ctx)

	zaplog.SUG.Info("gRPC demo completed")
}

func callRemoteService(ctx context.Context) {
	// Start APM transaction with gRPC outgoing context
	// The trace context will be auto injected into gRPC metadata
	txn, tracedCtx := elasticapm.StartApmTraceGrpcOutgoingCtx(
		ctx,
		"grpc-call-remote-service",
		"request",
	)
	defer txn.End()

	zaplog.SUG.Info("Starting gRPC call",
		zap.String("trace_id", txn.TraceContext().Trace.String()),
		zap.String("transaction_id", txn.TraceContext().Span.String()),
	)

	// Simulate preparing request
	prepareSpan := txn.StartSpan("prepare-request", "internal", nil)
	prepareRequest()
	prepareSpan.End()

	// Simulate gRPC call
	// In production code, you would pass tracedCtx to your gRPC client call:
	// response, err := grpcClient.Method(tracedCtx, request)
	grpcSpan := txn.StartSpan("grpc.Call", "external.grpc", nil)
	simulateGrpcCall(tracedCtx)
	grpcSpan.End()

	// Simulate processing response
	processSpan := txn.StartSpan("process-response", "internal", nil)
	processResponse()
	processSpan.End()

	zaplog.SUG.Info("gRPC call completed")
}

func prepareRequest() {
	// Simulate request preparation
	time.Sleep(20 * time.Millisecond)
	zaplog.SUG.Debug("Request prepared")
}

func simulateGrpcCall(ctx context.Context) {
	// Simulate gRPC network call
	// The trace context is already in the metadata thanks to StartApmTraceGrpcOutgoingCtx
	time.Sleep(100 * time.Millisecond)
	zaplog.SUG.Debug("gRPC call executed")
}

func processResponse() {
	// Simulate response processing
	time.Sleep(30 * time.Millisecond)
	zaplog.SUG.Debug("Response processed")
}

⬆️ Source: Source

Configuration Options

Field Type Description
Environment string Environment name (e.g., "production", "staging")
ServerUrl string Single APM server URL
ServerUrls []string Multiple APM server URLs
ApiKey string API key to authenticate with APM server
SecretToken string Secret token to authenticate with APM server
ServiceName string Name that identifies this service
ServiceVersion string Version of this service
NodeName string Name of node in multi-instance setup
ServerCertPath string Path to server certificate
SkipShortSpans bool Skip spans shorter than threshold

API Reference

Core Functions
  • Initialize(cfg *Config) error - Initialize APM with default options
  • InitializeWithOptions(cfg *Config, evo *EnvOption, setEnvs ...func()) error - Initialize with custom options
  • Close() - Flush and close APM tracing
  • SetLog(LOG apm.Logger) - Set custom logging
Version Functions
  • GetApmAgentVersion() string - Get current APM agent version
  • CheckApmAgentVersion(agentVersion string) bool - Verify version matching
gRPC Functions
  • StartApmTraceGrpcOutgoingCtx(ctx, name, apmTxnType) (*apm.Transaction, context.Context) - Start traced gRPC call
  • ContextWithTraceGrpcOutgoing(ctx, apmTransaction) context.Context - Add trace to context
  • ContextWithGrpcOutgoingTrace(ctx, apmTraceContext) context.Context - Add trace context to outgoing metadata

Advanced Usage

Environment Variable Configuration

The package supports configuration through environment variables. You can control whether to override existing variables:

cfg := &elasticapm.Config{
    Environment:    "production",
    ServerUrl:      "http://localhost:8200",
    ServiceName:    "my-service",
    ServiceVersion: "1.0.0",
}

envOption := &elasticapm.EnvOption{
    Override: true, // Override existing environment variables
}

must.Done(elasticapm.InitializeWithOptions(cfg, envOption))
defer elasticapm.Close()
Custom Logging Integration

Integrate with custom zap logging setup:

import (
    "github.com/yylego/elasticapm"
    "github.com/yylego/elasticapm/apmzaplog"
)

// Initialize APM with custom zap logging
must.Done(elasticapm.Initialize(cfg))
elasticapm.SetLog(apmzaplog.NewLog())
defer elasticapm.Close()
Context Propagation

When working with microservices, trace context needs to be passed between services:

// Service A: Start transaction
txn := apm.DefaultTracer().StartTransaction("external-call", "request")
ctx := apm.ContextWithTransaction(context.Background(), txn)

// Inject trace context into gRPC metadata
ctx = elasticapm.ContextWithTraceGrpcOutgoing(ctx, txn)

// Make gRPC call
response := grpcClient.Method(ctx, request)

txn.End()

Best Practices

Service Naming

Choose service names that reflect their function:

  • Use lowercase with hyphens: user-service, payment-gateway
  • Include team name when multiple teams share infrastructure: team-a-user-service
  • Keep names concise but descriptive
Environment Configuration

Set distinct environments to separate traces:

  • development - Development on your machine
  • staging - Pre-production testing
  • production - Live production traffic
  • testing - Automated test runs
Performance Optimization

To reduce overhead in high-throughput applications:

cfg := &elasticapm.Config{
    Environment:    "production",
    ServerUrl:      "http://localhost:8200",
    ServiceName:    "my-service",
    SkipShortSpans: true, // Skip spans shorter than threshold
}
Version Tracking

Always include semantic version in service configuration:

cfg := &elasticapm.Config{
    ServiceVersion: "1.2.3", // Semantic version
}

This helps correlate performance changes with deployments.

Troubleshooting

Connection Issues

If APM cannot connect to the server:

  1. Verify the server URL is accessible
  2. Check firewall settings allow outbound connections
  3. Verify API key is correct
  4. Check APM server logs
Missing Traces

If traces are not appearing in Kibana:

  1. Ensure transaction is ended: defer txn.End()
  2. Verify service name matches in Kibana filters
  3. Check environment setting matches what you expect
  4. Call Close() to flush pending data before exit
Version Mismatch

If you see errors about missing symbols:

# Check all dependencies use v2
go list -m all | grep elastic

Ensure all imports use go.elastic.co/apm/v2, not go.elastic.co/apm.

Version Compatibility

This package requires v2: go.elastic.co/apm/v2. It will not work with the v1.x package go.elastic.co/apm.

The version check functions ensure all dependencies use v2 to avoid the common pitfall of mixing v1 and v2 packages, which maintain separate tracing instances.

📄 License

MIT License. See LICENSE.


🤝 Contributing

Contributions are welcome! Report bugs, suggest features, and contribute code:

  • 🐛 Found a mistake? Open an issue on GitHub with reproduction steps
  • 💡 Have a feature idea? Create an issue to discuss the suggestion
  • 📖 Documentation confusing? Report it so we can improve
  • 🚀 Need new features? Share the use cases to help us understand requirements
  • Performance issue? Help us optimize through reporting slow operations
  • 🔧 Configuration problem? Ask questions about complex setups
  • 📢 Follow project progress? Watch the repo to get new releases and features
  • 🌟 Success stories? Share how this package improved the workflow
  • 💬 Feedback? We welcome suggestions and comments

🔧 Development

New code contributions, follow this process:

  1. Fork: Fork the repo on GitHub (using the webpage UI).
  2. Clone: Clone the forked project (git clone https://github.com/yourname/repo-name.git).
  3. Navigate: Navigate to the cloned project (cd repo-name)
  4. Branch: Create a feature branch (git checkout -b feature/xxx).
  5. Code: Implement the changes with comprehensive tests
  6. Testing: (Golang project) Ensure tests pass (go test ./...) and follow Go code style conventions
  7. Documentation: Update documentation to support client-facing changes and use significant commit messages
  8. Stage: Stage changes (git add .)
  9. Commit: Commit changes (git commit -m "Add feature xxx") ensuring backward compatible code
  10. Push: Push to the branch (git push origin feature/xxx).
  11. PR: Open a merge request on GitHub (on the GitHub webpage) with detailed description.

Please ensure tests pass and include relevant documentation updates.


🌟 Support

Welcome to contribute to this project via submitting merge requests and reporting issues.

Project Support:

  • Give GitHub stars if this project helps you
  • 🤝 Share with teammates and (golang) programming friends
  • 📝 Write tech blogs about development tools and workflows - we provide content writing support
  • 🌟 Join the ecosystem - committed to supporting open source and the (golang) development scene

Have Fun Coding with this package! 🎉🎉🎉


GitHub Stars

Stargazers

Documentation

Overview

Package elasticapm provides a simple and elegant wrapping of Elastic APM v2 Offers simple initialization, configuration management, and integration with zap logging Supports distributed tracing across HTTP and gRPC services

elasticapm 提供简洁优雅的 Elastic APM v2 封装 提供便捷的初始化、配置管理和 zap 日志集成 支持 HTTP 和 gRPC 服务的分布式追踪

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckApmAgentVersion

func CheckApmAgentVersion(agentVersion string) bool

CheckApmAgentVersion verifies that APM dependencies use v2 Returns false if version mismatch is detected This check prevents mixing v1 and v2 dependencies which maintain separate tracings

Important context from v1.15.0 to v2.0.0 upgrade: - v1: go.elastic.co/apm v1.15.0 - v2: go.elastic.co/apm/v2 v2.0.0 The v1 and v2 packages maintain independent defaultTracing instances

CheckApmAgentVersion 验证 APM 依赖是否使用 v2 如果检测到版本不匹配则返回 false 此检查防止混用 v1 和 v2 依赖,它们维护独立的追踪

从 v1.15.0 升级到 v2.0.0 的重要背景: - v1: go.elastic.co/apm v1.15.0 - v2: go.elastic.co/apm/v2 v2.0.0 v1 和 v2 包维护独立的 defaultTracing 实例

func Close

func Close()

Close flushes pending data and closes the APM tracing Should be called before application shutdown to ensure data is sent Logs tracing statistics when monitoring is needed

Close 刷新待处理数据并关闭 APM 追踪 应在应用关闭前调用以确保数据发送完成 在需要监控时记录追踪统计信息

func ContextWithGrpcOutgoingTrace

func ContextWithGrpcOutgoingTrace(ctx context.Context, apmTraceContext apm.TraceContext) context.Context

ContextWithGrpcOutgoingTrace injects W3C trace headers into gRPC outgoing metadata Adds traceparent and tracestate headers enabling distributed tracing Headers are set in lowercase ensuring correct gRPC metadata handling

ContextWithGrpcOutgoingTrace 将 W3C 追踪头注入 gRPC 出站元数据 添加 traceparent 和 tracestate 头实现分布式追踪 头信息使用小写确保正确处理 gRPC 元数据

func ContextWithTraceGrpcOutgoing

func ContextWithTraceGrpcOutgoing(ctx context.Context, apmTransaction *apm.Transaction) context.Context

ContextWithTraceGrpcOutgoing attaches transaction to context and adds gRPC outgoing trace headers First adds the transaction to context, then injects trace metadata Propagates traces across gRPC service boundaries

ContextWithTraceGrpcOutgoing 将事务附加到上下文并添加 gRPC 出站追踪头 首先将事务添加到上下文,然后注入追踪元数据 跨 gRPC 服务边界传播追踪

func GetApmAgentVersion

func GetApmAgentVersion() string

GetApmAgentVersion returns the current APM agent version string Version matches the project's go.elastic.co/apm/v2 package version

Examples: - If project uses go.elastic.co/apm/v2 v2.6.3, returns "2.6.3" - If project uses go.elastic.co/apm/v2 v2.7.0, returns "2.7.0" - If project uses go.elastic.co/apm v1.15.0, this returns v2 version (not 1.15.0)

Recommendation: New projects should use go.elastic.co/apm/v2

GetApmAgentVersion 返回当前 APM agent 版本字符串 版本与项目的 go.elastic.co/apm/v2 包版本匹配

示例: - 如果项目使用 go.elastic.co/apm/v2 v2.6.3,返回 "2.6.3" - 如果项目使用 go.elastic.co/apm/v2 v2.7.0,返回 "2.7.0" - 如果项目使用 go.elastic.co/apm v1.15.0,这里返回 v2 版本(不是 1.15.0)

建议:新项目应使用 go.elastic.co/apm/v2

func Initialize

func Initialize(cfg *Config) error

Initialize sets up the APM tracing with given config and default options Uses "go.elastic.co/apm/v2" instead of the old "go.elastic.co/apm" Sets up zap logging integration with APM logs

Initialize 使用给定配置和默认选项初始化 APM 追踪 使用 "go.elastic.co/apm/v2" 而非旧版 "go.elastic.co/apm" 设置 zap 日志与 APM 日志的集成

func InitializeWithOptions

func InitializeWithOptions(cfg *Config, evo *EnvOption, setEnvs ...func()) error

InitializeWithOptions sets up APM with custom environment options Allows fine-grained controls on environment variable handling Extra setup functions can be passed when custom configuration is needed

InitializeWithOptions 使用自定义环境选项初始化 APM 允许对环境变量处理进行精细控制 可传递额外的设置函数进行自定义配置

func SetLog

func SetLog(LOG apm.Logger)

SetLog sets a custom logging implementation with APM tracing Replaces the default logging with the provided implementation

SetLog 设置自定义日志实现与 APM 追踪 用提供的实现替换默认日志

func StartApmTraceGrpcOutgoingCtx

func StartApmTraceGrpcOutgoingCtx(ctx context.Context, name, apmTxnType string) (*apm.Transaction, context.Context)

StartApmTraceGrpcOutgoingCtx starts a new APM transaction and injects trace context into gRPC metadata Returns the transaction and context prepared to make outgoing gRPC calls The context contains W3C trace headers enabling distributed tracing

StartApmTraceGrpcOutgoingCtx 启动新的 APM 事务并将追踪上下文注入 gRPC 元数据 返回事务和准备好的上下文用于出站 gRPC 调用 上下文包含 W3C 追踪头实现分布式追踪

Types

type Config

type Config struct {
	Environment    string   // Environment name (e.g., "production", "staging") // 环境名称(如 "production"、"staging")
	ServerUrls     []string // Multiple APM servers URLs // 多个 APM 服务地址
	ServerUrl      string   // Single APM URL // 单个 APM 地址
	ApiKey         string   `json:"-"` // API key used in authentication (not logged) // API 密钥用于认证(不记录日志)
	SecretToken    string   `json:"-"` // Secret token used in authentication (not logged) // Secret Token 用于认证(不记录日志)
	ServiceName    string   // Service name used in identification // 服务名称用于标识
	ServiceVersion string   // Service version // 服务版本
	NodeName       string   // Node name used in multi-instance services // 节点名称用于多实例服务
	ServerCertPath string   // Path to certificate used in TLS // TLS 证书路径
	SkipShortSpans bool     // Skip spans when duration is too short // 跳过持续时间过短的 span
}

Config holds configuration used when initializing Elastic APM Contains connection details, authentication credentials, and service metadata Environment variables are set based on these values during initialization

Config 保存 Elastic APM 初始化配置 包含连接详情、认证凭据和服务元数据 初始化时根据这些值设置环境变量

func (*Config) SetEnv

func (cfg *Config) SetEnv(evo *EnvOption)

SetEnv configures environment variables based on config values Uses EnvOption to decide on overriding existing variables Maps config fields to ELASTIC_APM_* environment variables

SetEnv 根据配置值设置环境变量 使用 EnvOption 决定是否覆盖现有变量 将配置字段映射到 ELASTIC_APM_* 环境变量

type EnvOption

type EnvOption struct {
	Override bool // Override existing env vars when true // 当值是 true 时覆盖现有环境变量
}

EnvOption controls how environment variables are set during initialization When Override is false, existing environment variables are kept unchanged

EnvOption 控制初始化时如何设置环境变量 当 Override 是 false 时,保留现有的环境变量

func NewEnvOption

func NewEnvOption() *EnvOption

NewEnvOption creates a new EnvOption with Override enabled Returns instance that overrides existing environment variables

NewEnvOption 创建启用 Override 的新 EnvOption 返回会覆盖现有环境变量的实例

func (*EnvOption) SetEnv

func (op *EnvOption) SetEnv(name, value string)

SetEnv sets an environment variable based on the Override setting When Override is true, sets the variable without conditions When Override is false, sets the variable if it is not yet defined

SetEnv 根据 Override 设置设定环境变量 当 Override 是 true 时,无条件设置变量 当 Override 是 false 时,在变量未定义时才设置

Directories

Path Synopsis
Package apmzaplog provides zap logging integration with Elastic APM Implements apm.Logging interface to route APM logs through zap Uses frame skipping to ensure correct source location in logs
Package apmzaplog provides zap logging integration with Elastic APM Implements apm.Logging interface to route APM logs through zap Uses frame skipping to ensure correct source location in logs
internal
demos/demo1x command
demos/demo2x command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL