Help us shape the future of Go! Take the 2026 Go Developer Survey

snmptrapreceiver

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

SNMP Trap Receiver for the OpenTelemetry Collector

Status
Stability development: logs
Distributions none yet, build with ocb
Contrib donation open-telemetry/opentelemetry-collector-contrib#50849 (draft, sponsor needed)
Tracking issue open-telemetry/opentelemetry-collector-contrib#32358
Code owner @Mesverrum

The SNMP Trap Receiver listens for SNMPv1/v2c (optional v3 USM) traps and informs over UDP and converts each PDU to an OpenTelemetry log.

A trap is an event (linkDown, coldStart, vendor fault). Emitting a metric series per trap OID/source is the wrong signal. Volume for dashboards is log count.

This module is the collector-shaped core of otelcol.receiver.snmptrap, which already runs in Mesverrum/alloy on a lab fabric. The Alloy-only pieces (targets, device join, Fleet) are not here. The same code is up for donation to contrib in #50849; this repository is the standalone home the contrib process asks for while that PR looks for a sponsor.

Looking for a sponsor and codeowners

The contrib donation needs a sponsor (an approver or maintainer at a company other than mine) and two more codeowners. If you run traps in production and want a listener in the collector, open an issue here or comment on #50849. I will keep maintaining the implementation either way.

Build a collector with it

Until the donation lands, include the receiver with the OpenTelemetry Collector Builder. builder-config.yaml in this repo is a working manifest:

go install go.opentelemetry.io/collector/cmd/builder@v0.160.0
builder --config builder-config.yaml
./dist/otelcol-snmptrap --config example-config.yaml

Then point a device trap-group at the collector host and port and watch the debug exporter. example-config.yaml lists every setting with its default.

By default the receiver binds 0.0.0.0:1620. Privileged :162 needs CAP_NET_BIND_SERVICE or DNAT.

receivers:
  snmptrap:
    listen_address: 0.0.0.0:1620
    # empty communities = accept all (common field practice)
    communities: [public]
    mib_paths: [/etc/snmp/mibs]
    attributes:
      job: snmptrap

exporters:
  debug:
    verbosity: detailed

service:
  pipelines:
    logs:
      receivers: [snmptrap]
      exporters: [debug]

Configuration

Field Description Default
listen_address UDP bind host:port 0.0.0.0:1620
communities v1/v2c allowlist. Empty = accept all []
include_community Put the community string on the log (off by default) false
drop_undefined Drop traps whose trap OID did not resolve via MIBs false
mib_paths Directories of SMI/MIB files for gosmi name enrichment []
attributes Extra log attributes stamped on every record {}
v3 Optional USM user. When set, the listener is v3-only unset
v3
Field Description
user USM user (required when v3 is set)
security_level noAuthNoPriv (default), authNoPriv, authPriv
auth_protocol MD5, SHA, SHA224, SHA256, SHA384, SHA512
auth_password Auth passphrase
priv_protocol DES, AES, AES192, AES192C, AES256, AES256C
priv_password Privacy passphrase

gosnmp still documents v3 trap listen as less battle-tested than v2c.

Data format

Each PDU becomes one log record.

Body: compact JSON (source, trap_oid, trap_name, varbinds, …).

Attributes: source, trap_oid, trap_name, trap_mib, snmp_version, pdu_type, plus any attributes map entries. Optional agent_address, engine_id, context_name, community.

Timestamps: Timestamp is receive time; ObservedTimestamp is now.

MIB lookup is fail-open. Missing names stay numeric OIDs.

UDP receive never blocks: a full in-memory queue drops the trap.

Development

make test     # go test ./...
make cover    # coverage summary
make lint     # go vet + gofmt check
make generate # regenerate internal/metadata from metadata.yaml

Layout follows a contrib receiver so the code moves into receiver/snmptrapreceiver unchanged apart from the module path.

License

Apache 2.0. See LICENSE. Files carry the OpenTelemetry Authors header because they are written for donation to the OpenTelemetry project.

Documentation

Overview

Package snmptrapreceiver listens for SNMP traps and informs and emits OpenTelemetry logs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CommunityAllowed

func CommunityAllowed(allow []string, got string) bool

CommunityAllowed reports whether a v1/v2c community is accepted. An empty allowlist accepts every community.

func GoSNMPParams

func GoSNMPParams(cfg ListenConfig, log *slog.Logger) (*gosnmp.GoSNMP, error)

GoSNMPParams builds gosnmp listener parameters. v3 is optional; omit it for v1/v2c. When V3 is set the listener is v3-only.

func ListenChanged

func ListenChanged(old, new ListenConfig) bool

ListenChanged reports whether the UDP bind / auth / MIB tree changed.

func NewFactory

func NewFactory() receiver.Factory

NewFactory creates a factory for the SNMP trap receiver.

func NormalizeOID

func NormalizeOID(oid string) string

NormalizeOID strips a leading dot.

func PDUKind

func PDUKind(t gosnmp.PDUType) string

PDUKind is "inform" or "trap" for metrics.

Types

type Config

type Config struct {
	// ListenAddress is the UDP host:port. Default 0.0.0.0:1620.
	ListenAddress string `mapstructure:"listen_address"`
	// Communities is a v1/v2c allowlist. Empty accepts every community.
	Communities []string `mapstructure:"communities"`
	// IncludeCommunity puts the community string on the log record.
	IncludeCommunity bool `mapstructure:"include_community"`
	// DropUndefined drops traps whose trap OID did not resolve via MIBs.
	DropUndefined bool `mapstructure:"drop_undefined"`
	// MIBPaths are directories of SMI/MIB files for optional gosmi enrichment.
	MIBPaths []string `mapstructure:"mib_paths"`
	// Attributes are extra log attributes stamped on every record.
	Attributes map[string]string `mapstructure:"attributes"`
	// V3 is an optional USM user. When set, the listener is v3-only.
	V3 *V3Config `mapstructure:"v3"`
}

Config is the receiver config in the collector config.yaml.

func (*Config) Validate

func (cfg *Config) Validate() error

Validate checks the configuration.

type DecodeOptions

type DecodeOptions struct {
	IncludeCommunity bool
	Translator       Translator
}

DecodeOptions control optional fields on the record.

type GosmiTranslator

type GosmiTranslator struct {
	// contains filtered or unexported fields
}

GosmiTranslator looks up OIDs with gosmi. Init and module load are process-global.

func (*GosmiTranslator) Lookup

func (g *GosmiTranslator) Lookup(oid string) (Lookup, error)

Lookup implements Translator.

type ListenConfig

type ListenConfig struct {
	ListenAddress    string
	Communities      []string
	IncludeCommunity bool
	DropUndefined    bool
	MIBPaths         []string
	V3               *V3Config
}

ListenConfig is the UDP listener + USM settings shared by the OTel receiver.

type Lookup

type Lookup struct {
	Name string
	MIB  string
}

Lookup is a best-effort MIB name for an OID.

type NoopTranslator

type NoopTranslator struct{}

NoopTranslator never resolves names.

func (NoopTranslator) Lookup

func (NoopTranslator) Lookup(oid string) (Lookup, error)

Lookup implements Translator.

type Record

type Record struct {
	Time         time.Time `json:"time"`
	Source       string    `json:"source"`
	Version      string    `json:"version"`
	PDUType      string    `json:"pdu_type"`
	TrapOID      string    `json:"trap_oid"`
	TrapName     string    `json:"trap_name,omitempty"`
	MIB          string    `json:"mib,omitempty"`
	Community    string    `json:"community,omitempty"`
	EngineID     string    `json:"engine_id,omitempty"`
	ContextName  string    `json:"context_name,omitempty"`
	AgentAddress string    `json:"agent_address,omitempty"`
	Enterprise   string    `json:"enterprise,omitempty"`
	GenericTrap  *int      `json:"generic_trap,omitempty"`
	SpecificTrap *int      `json:"specific_trap,omitempty"`
	SysUpTime    uint      `json:"sys_up_time,omitempty"`
	Varbinds     []Varbind `json:"varbinds"`
}

Record is one trap or inform, ready to marshal as an OTel log body.

func Decode

func Decode(packet *gosnmp.SnmpPacket, addr *net.UDPAddr, now time.Time, opts DecodeOptions) Record

Decode turns a gosnmp trap/inform packet into a Record.

func (Record) MarshalJSONLine

func (r Record) MarshalJSONLine() ([]byte, error)

MarshalJSONLine is compact JSON for the OTel log body.

func (Record) Resolved

func (r Record) Resolved() bool

Resolved reports whether trap identity was enriched past a numeric OID.

type Translator

type Translator interface {
	Lookup(oid string) (Lookup, error)
}

Translator resolves OIDs to textual names. Misses must not be fatal.

func NewGosmiTranslator

func NewGosmiTranslator(paths []string, log *slog.Logger) (Translator, error)

NewGosmiTranslator initializes gosmi (once) and loads modules from dirs. Load failures are logged and skipped. An empty path list returns NoopTranslator.

type V3Config

type V3Config struct {
	User          string `mapstructure:"user"`
	SecurityLevel string `mapstructure:"security_level"`
	AuthProtocol  string `mapstructure:"auth_protocol"`
	AuthPassword  string `mapstructure:"auth_password"`
	PrivProtocol  string `mapstructure:"priv_protocol"`
	PrivPassword  string `mapstructure:"priv_password"`
}

V3Config is a single USM user for SNMPv3 traps/informs.

type Varbind

type Varbind struct {
	OID   string `json:"oid"`
	Name  string `json:"name,omitempty"`
	Type  string `json:"type"`
	Value any    `json:"value"`
}

Varbind is one decoded PDU variable.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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