Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add kernelVersion to telemetry traces #1094

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pkg/telemetry/heartbeat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package telemetry

import (
"context"
"fmt"
"os/exec"
"runtime"
"strings"

"github.com/pkg/errors"
)

// HostInfoClient is a collection of functionality for retrieving
// information about the host.
type HostInfoClient struct{}

// KernelVersion returs the version of the kernel running on the host system.
func (p *HostInfoClient) KernelVersion(ctx context.Context) (string, error) {
var cmd *exec.Cmd

switch runtime.GOOS {
case "windows":
cmd = exec.CommandContext(ctx, "powershell", "-command", "$([Environment]::OSVersion).VersionString")
case "linux":
cmd = exec.CommandContext(ctx, "uname", "-r")
default:
return "", fmt.Errorf("unsupported platform %q", runtime.GOOS)

Check failure on line 27 in pkg/telemetry/heartbeat.go

View workflow job for this annotation

GitHub Actions / Lint (linux, amd64)

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"unsupported platform %q\", runtime.GOOS)" (err113)

Check failure on line 27 in pkg/telemetry/heartbeat.go

View workflow job for this annotation

GitHub Actions / Lint (linux, arm64)

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"unsupported platform %q\", runtime.GOOS)" (err113)

Check failure on line 27 in pkg/telemetry/heartbeat.go

View workflow job for this annotation

GitHub Actions / Lint (windows, amd64)

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"unsupported platform %q\", runtime.GOOS)" (err113)

Check failure on line 27 in pkg/telemetry/heartbeat.go

View workflow job for this annotation

GitHub Actions / Lint (windows, arm64)

do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"unsupported platform %q\", runtime.GOOS)" (err113)
}

output, err := cmd.CombinedOutput()
if err != nil {
return "", errors.Wrapf(err, "failed to get %s kernel version: %s", runtime.GOOS, string(output))
}
return strings.TrimSuffix(string(output), "\n"), nil
}
23 changes: 0 additions & 23 deletions pkg/telemetry/heartbeat_unix.go

This file was deleted.

3 changes: 2 additions & 1 deletion pkg/telemetry/heartbeat_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ func TestLinuxPlatformKernelVersion(t *testing.T) {
InitAppInsights("", "")
ctx := context.TODO()

str, err := KernelVersion(ctx)
client := &HostInfoClient{}
str, err := client.KernelVersion(ctx)
require.NoError(t, err)
require.NotEmpty(t, str)
}
21 changes: 0 additions & 21 deletions pkg/telemetry/heartbeat_windows.go

This file was deleted.

3 changes: 2 additions & 1 deletion pkg/telemetry/heartbeat_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ func TestWindowsGetKernelVersion(t *testing.T) {
InitAppInsights("", "")
ctx := context.TODO()

str, err := KernelVersion(ctx)
client := &HostInfoClient{}
str, err := client.KernelVersion(ctx)
require.NoError(t, err)
require.NotEmpty(t, str)
}
28 changes: 23 additions & 5 deletions pkg/telemetry/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ var (
client appinsights.TelemetryClient
version string
mbShift uint64 = 20

// property keys
kernelversion = "kernelversion"
sysmem = "sysmem"
Expand Down Expand Up @@ -86,6 +85,10 @@ type TelemetryClient struct {
processName string
properties map[string]string
profile Perf

kernelInfoClient interface {
KernelVersion(context.Context) (string, error)
}
}

func NewAppInsightsTelemetryClient(processName string, additionalproperties map[string]string) (*TelemetryClient, error) {
Expand All @@ -105,9 +108,10 @@ func NewAppInsightsTelemetryClient(processName string, additionalproperties map[
}

return &TelemetryClient{
processName: processName,
properties: properties,
profile: perfProfile,
processName: processName,
kernelInfoClient: &HostInfoClient{},
properties: properties,
profile: perfProfile,
}, nil
}

Expand Down Expand Up @@ -161,7 +165,7 @@ func (t *TelemetryClient) trackWarning(err error, msg string) {
}

func (t *TelemetryClient) heartbeat(ctx context.Context) {
kernelVersion, err := KernelVersion(ctx)
kernelVersion, err := t.kernelInfoClient.KernelVersion(ctx)
if err != nil {
t.trackWarning(err, "failed to get kernel version")
}
Expand Down Expand Up @@ -224,6 +228,20 @@ func (t *TelemetryClient) TrackMetric(metricname string, value float64, properti

func (t *TelemetryClient) TrackTrace(name string, severity contracts.SeverityLevel, properties map[string]string) {
trace := appinsights.NewTraceTelemetry(name, severity)

kernelVersion, err := t.kernelInfoClient.KernelVersion(context.Background())
if err != nil {
if client != nil {
errtrace := appinsights.NewTraceTelemetry(fmt.Sprintf("failed to get kernel version for trace: %v", err), contracts.Error)
for k, v := range t.properties {
errtrace.Properties[k] = v
}
client.Track(errtrace)
}
} else {
properties[kernelversion] = kernelVersion
}

if t.properties != nil {
t.RLock()
for k, v := range t.properties {
Expand Down
35 changes: 35 additions & 0 deletions pkg/telemetry/telemetry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"
"testing"

"github.com/microsoft/ApplicationInsights-Go/appinsights"
"github.com/stretchr/testify/require"
)

Expand All @@ -22,6 +23,40 @@ func TestNewAppInsightsTelemetryClient(t *testing.T) {
require.NotPanics(t, func() { NewAppInsightsTelemetryClient("test", map[string]string{}) })
}

type MockKernelVersionClient struct {
KernelVersionF func(context.Context) (string, error)
}

func (m *MockKernelVersionClient) KernelVersion(ctx context.Context) (string, error) {
return m.KernelVersionF(ctx)
}

func TestTrackTraceIncludesKernelVersion(t *testing.T) {
mockKernelVersion := "5.15.0-101-generic"
called := false
mockClient := &MockKernelVersionClient{
KernelVersionF: func(_ context.Context) (string, error) {
called = true
return mockKernelVersion, nil
},
}

client := &TelemetryClient{
kernelInfoClient: mockClient,
properties: map[string]string{
"test_key": "test_value",
},
}

traceProperties := map[string]string{}

client.TrackTrace("test_trace_event", appinsights.Information, traceProperties)

require.Equal(t, mockKernelVersion, traceProperties[kernelversion], "kernelVersion should be included in trace properties")

require.True(t, called, "expected KernelVersion to be called but wasn't")
}

func TestGetEnvironmentProerties(t *testing.T) {
properties := GetEnvironmentProperties()

Expand Down
Loading