Skip to content

Commit

Permalink
new opentelemetry logger
Browse files Browse the repository at this point in the history
  • Loading branch information
dmachard committed Dec 22, 2024
1 parent 15360f3 commit 9024d8f
Show file tree
Hide file tree
Showing 21 changed files with 601 additions and 50 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
- [`File`](docs/loggers/logger_file.md) with automatic rotation and compression
- *Provide metrics and API*
- [`Prometheus`](docs/loggers/logger_prometheus.md) exporter
- [`OpenTelemetry`](docs/loggers/logger_opentelemetry.md) tracing dns
- [`Statsd`](docs/loggers/logger_statsd.md) support
- [`REST API`](docs/loggers/logger_restapi.md) with [swagger](https://generator.swagger.io/?url=https://raw.githubusercontent.com/dmachard/go-dnscollector/main/docs/swagger.yml) to search DNS domains
- *Send to remote host with generic transport protocol*
Expand Down
32 changes: 15 additions & 17 deletions dnsutils/dnsmessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,10 @@ import (
)

var (
DNSQuery = "QUERY"
DNSQueryQuiet = "Q"
DNSReply = "REPLY"
DNSReplyQuiet = "R"
PdnsDirectives = regexp.MustCompile(`^powerdns-*`)
GeoIPDirectives = regexp.MustCompile(`^geoip-*`)
SuspiciousDirectives = regexp.MustCompile(`^suspicious-*`)
PublicSuffixDirectives = regexp.MustCompile(`^publixsuffix-*`)
ExtractedDirectives = regexp.MustCompile(`^extracted-*`)
ReducerDirectives = regexp.MustCompile(`^reducer-*`)
MachineLearningDirectives = regexp.MustCompile(`^ml-*`)
FilteringDirectives = regexp.MustCompile(`^filtering-*`)
RawTextDirective = regexp.MustCompile(`^ *\{.*\}`)
ATagsDirectives = regexp.MustCompile(`^atags*`)
DNSQuery = "QUERY"
DNSQueryQuiet = "Q"
DNSReply = "REPLY"
DNSReplyQuiet = "R"
)

type DNSAnswer struct {
Expand Down Expand Up @@ -112,7 +102,7 @@ type DNSTap struct {
QueryZone string `json:"query-zone"`
}

type PowerDNS struct {
type CollectorPowerDNS struct {
Tags []string `json:"tags"`
OriginalRequestSubnet string `json:"original-request-subnet"`
AppliedPolicy string `json:"applied-policy"`
Expand All @@ -129,6 +119,10 @@ type PowerDNS struct {
DeviceID string `json:"device-id"`
}

type LoggerOpenTelemetry struct {
TraceID string `json:"trace-id"`
}

type TransformDNSGeo struct {
City string `json:"city"`
Continent string `json:"continent"`
Expand Down Expand Up @@ -209,8 +203,9 @@ type DNSMessage struct {
DNS DNS `json:"dns"`
EDNS DNSExtended `json:"edns"`
DNSTap DNSTap `json:"dnstap"`
PowerDNS *CollectorPowerDNS `json:"powerdns,omitempty"`
OpenTelemetry *LoggerOpenTelemetry `json:"opentelemetry,omitempty"`
Geo *TransformDNSGeo `json:"geoip,omitempty"`
PowerDNS *PowerDNS `json:"powerdns,omitempty"`
Suspicious *TransformSuspicious `json:"suspicious,omitempty"`
PublicSuffix *TransformPublicSuffix `json:"publicsuffix,omitempty"`
Extracted *TransformExtracted `json:"extracted,omitempty"`
Expand Down Expand Up @@ -264,14 +259,17 @@ func (dm *DNSMessage) Init() {
}

func (dm *DNSMessage) InitTransforms() {
// init transforms
dm.ATags = &TransformATags{}
dm.Filtering = &TransformFiltering{}
dm.MachineLearning = &TransformML{}
dm.Reducer = &TransformReducer{}
dm.Extracted = &TransformExtracted{}
dm.PublicSuffix = &TransformPublicSuffix{}
dm.Suspicious = &TransformSuspicious{}
dm.PowerDNS = &PowerDNS{}
dm.Geo = &TransformDNSGeo{}
dm.Relabeling = &TransformRelabeling{}
// init collectors & loggers
dm.PowerDNS = &CollectorPowerDNS{}
dm.OpenTelemetry = &LoggerOpenTelemetry{}
}
47 changes: 45 additions & 2 deletions dnsutils/dnsmessage_json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func TestDnsMessage_Json_Collectors_Reference(t *testing.T) {
}{
{
collector: "powerdns",
dmRef: DNSMessage{PowerDNS: &PowerDNS{
dmRef: DNSMessage{PowerDNS: &CollectorPowerDNS{
OriginalRequestSubnet: "subnet",
AppliedPolicy: "basicrpz",
AppliedPolicyHit: "hit",
Expand Down Expand Up @@ -164,6 +164,49 @@ func TestDnsMessage_Json_Collectors_Reference(t *testing.T) {
}
}

func TestDnsMessage_Json_Loggers_Reference(t *testing.T) {
testcases := []struct {
logger string
dmRef DNSMessage
jsonRef string
}{
{
logger: "otel",
dmRef: DNSMessage{OpenTelemetry: &LoggerOpenTelemetry{
TraceID: "27c3e94ad6284eec9a50cfc5bd7384d6",
}},

jsonRef: `{
"opentelemetry": {
"trace-id": "27c3e94ad6284eec9a50cfc5bd7384d6"
}
}`,
},
}
for _, tc := range testcases {
t.Run(tc.logger, func(t *testing.T) {

tc.dmRef.Init()

var dmMap map[string]interface{}
err := json.Unmarshal([]byte(tc.dmRef.ToJSON()), &dmMap)
if err != nil {
t.Fatalf("could not unmarshal dm json: %s\n", err)
}

var refMap map[string]interface{}
err = json.Unmarshal([]byte(tc.jsonRef), &refMap)
if err != nil {
t.Fatalf("could not unmarshal ref json: %s\n", err)
}

if !reflect.DeepEqual(dmMap[tc.logger], refMap[tc.logger]) {
t.Errorf("json format different from reference, Get=%s Want=%s", dmMap[tc.logger], refMap[tc.logger])
}
})
}
}

func TestDnsMessage_Json_Transforms_Reference(t *testing.T) {

testcases := []struct {
Expand Down Expand Up @@ -558,7 +601,7 @@ func TestDnsMessage_JsonFlatten_Collectors_Reference(t *testing.T) {
}{
{
collector: "powerdns",
dm: DNSMessage{PowerDNS: &PowerDNS{
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{
OriginalRequestSubnet: "subnet",
AppliedPolicy: "basicrpz",
AppliedPolicyHit: "hit",
Expand Down
36 changes: 36 additions & 0 deletions dnsutils/dnsmessage_text.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,40 @@ import (
"errors"
"fmt"
"log"
"regexp"
"strconv"
"strings"
"time"
)

var (
OtelDirectives = regexp.MustCompile(`^otel-*`)
PdnsDirectives = regexp.MustCompile(`^powerdns-*`)
GeoIPDirectives = regexp.MustCompile(`^geoip-*`)
SuspiciousDirectives = regexp.MustCompile(`^suspicious-*`)
PublicSuffixDirectives = regexp.MustCompile(`^publixsuffix-*`)
ExtractedDirectives = regexp.MustCompile(`^extracted-*`)
ReducerDirectives = regexp.MustCompile(`^reducer-*`)
MachineLearningDirectives = regexp.MustCompile(`^ml-*`)
FilteringDirectives = regexp.MustCompile(`^filtering-*`)
RawTextDirective = regexp.MustCompile(`^ *\{.*\}`)
ATagsDirectives = regexp.MustCompile(`^atags*`)
)

func (dm *DNSMessage) handleOpenTelemetryDirectives(directive string, s *strings.Builder) error {
if dm.OpenTelemetry == nil {
s.WriteString("-")
} else {
switch {
case directive == "otel-trace-id":
s.WriteString(dm.OpenTelemetry.TraceID)
default:
return errors.New(ErrorUnexpectedDirective + directive)
}
}
return nil
}

func (dm *DNSMessage) handleGeoIPDirectives(directive string, s *strings.Builder) error {
if dm.Geo == nil {
s.WriteString("-")
Expand Down Expand Up @@ -532,6 +561,13 @@ func (dm *DNSMessage) ToTextLine(format []string, fieldDelimiter string, fieldBo
s.WriteByte('-')
}

// more directives from loggers
case OtelDirectives.MatchString(directive):
err := dm.handleOpenTelemetryDirectives(directive, &s)
if err != nil {
return nil, err
}

// more directives from collectors
case PdnsDirectives.MatchString(directive):
err := dm.handlePdnsDirectives(directive, &s)
Expand Down
65 changes: 51 additions & 14 deletions dnsutils/dnsmessage_text_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func TestDnsMessage_TextFormat_InvalidDirectives(t *testing.T) {
},
{
name: "powerdns",
dm: DNSMessage{PowerDNS: &PowerDNS{}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{}},
format: "powerdns-invalid",
},
{
Expand Down Expand Up @@ -395,6 +395,43 @@ func TestDnsMessage_TextFormat_Directives_Geo(t *testing.T) {
}
}

func TestDnsMessage_TextFormat_Directives_OpenTelemetry(t *testing.T) {
config := pkgconfig.GetDefaultConfig()

testcases := []struct {
name string
format string
dm DNSMessage
expected string
}{
{
name: "undefined",
format: "otel-trace-id",
dm: DNSMessage{},
expected: "-",
},
{
name: "default",
format: "otel-trace-id",
dm: DNSMessage{OpenTelemetry: &LoggerOpenTelemetry{TraceID: "27c3e94ad6284eec9a50cfc5bd7384d6"}},
expected: "27c3e94ad6284eec9a50cfc5bd7384d6",
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
line := tc.dm.String(
strings.Fields(tc.format),
config.Global.TextFormatDelimiter,
config.Global.TextFormatBoundary,
)
if line != tc.expected {
t.Errorf("Want: %s, got: %s", tc.expected, line)
}
})
}
}

func TestDnsMessage_TextFormat_Directives_Pdns(t *testing.T) {
config := pkgconfig.GetDefaultConfig()

Expand All @@ -413,13 +450,13 @@ func TestDnsMessage_TextFormat_Directives_Pdns(t *testing.T) {
{
name: "empty_attributes",
format: "powerdns-tags powerdns-applied-policy powerdns-original-request-subnet powerdns-metadata",
dm: DNSMessage{PowerDNS: &PowerDNS{}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{}},
expected: "- - - -",
},
{
name: "applied_policy",
format: "powerdns-applied-policy powerdns-applied-policy-hit powerdns-applied-policy-kind powerdns-applied-policy-trigger powerdns-applied-policy-type",
dm: DNSMessage{PowerDNS: &PowerDNS{
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{
AppliedPolicy: "policy",
AppliedPolicyHit: "hit",
AppliedPolicyKind: "kind",
Expand All @@ -431,67 +468,67 @@ func TestDnsMessage_TextFormat_Directives_Pdns(t *testing.T) {
{
name: "original_request_subnet",
format: "powerdns-original-request-subnet",
dm: DNSMessage{PowerDNS: &PowerDNS{OriginalRequestSubnet: "test"}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{OriginalRequestSubnet: "test"}},
expected: "test",
},
{
name: "metadata_badsyntax",
format: "powerdns-metadata",
dm: DNSMessage{PowerDNS: &PowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
expected: "-",
},
{
name: "metadata",
format: "powerdns-metadata:test_key1",
dm: DNSMessage{PowerDNS: &PowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
expected: "test_value1",
},
{
name: "metadata_invalid",
format: "powerdns-metadata:test_key2",
dm: DNSMessage{PowerDNS: &PowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Metadata: map[string]string{"test_key1": "test_value1"}}},
expected: "-",
},
{
name: "tags_all",
format: "powerdns-tags",
dm: DNSMessage{PowerDNS: &PowerDNS{Tags: []string{"tag1", "tag2"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Tags: []string{"tag1", "tag2"}}},
expected: "tag1,tag2",
},
{
name: "tags_index",
format: "powerdns-tags:1",
dm: DNSMessage{PowerDNS: &PowerDNS{Tags: []string{"tag1", "tag2"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Tags: []string{"tag1", "tag2"}}},
expected: "tag2",
},
{
name: "tags_invalid_index",
format: "powerdns-tags:3",
dm: DNSMessage{PowerDNS: &PowerDNS{Tags: []string{"tag1", "tag2"}}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{Tags: []string{"tag1", "tag2"}}},
expected: "-",
},
{
name: "message_id",
format: "powerdns-message-id",
dm: DNSMessage{PowerDNS: &PowerDNS{MessageID: "27c3e94ad6284eec9a50cfc5bd7384d6"}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{MessageID: "27c3e94ad6284eec9a50cfc5bd7384d6"}},
expected: "27c3e94ad6284eec9a50cfc5bd7384d6",
},
{
name: "initial_requestor_id",
format: "powerdns-initial-requestor-id",
dm: DNSMessage{PowerDNS: &PowerDNS{InitialRequestorID: "5e006236c8a74f7eafc6af126e6d0689"}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{InitialRequestorID: "5e006236c8a74f7eafc6af126e6d0689"}},
expected: "5e006236c8a74f7eafc6af126e6d0689",
},
{
name: "requestor_id",
format: "powerdns-requestor-id",
dm: DNSMessage{PowerDNS: &PowerDNS{RequestorID: "5e006236c8a74f7eafc6af126e6d0689"}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{RequestorID: "5e006236c8a74f7eafc6af126e6d0689"}},
expected: "5e006236c8a74f7eafc6af126e6d0689",
},
{
name: "device_id_name",
format: "powerdns-device-id powerdns-device-name",
dm: DNSMessage{PowerDNS: &PowerDNS{DeviceID: "5e006236c8a74f7eafc6af126e6d0689", DeviceName: "test"}},
dm: DNSMessage{PowerDNS: &CollectorPowerDNS{DeviceID: "5e006236c8a74f7eafc6af126e6d0689", DeviceName: "test"}},
expected: "5e006236c8a74f7eafc6af126e6d0689 test",
},
}
Expand Down
Loading

0 comments on commit 9024d8f

Please sign in to comment.