-
Notifications
You must be signed in to change notification settings - Fork 480
/
Copy pathdotnet.go
156 lines (131 loc) · 6.33 KB
/
dotnet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package instrumentation
import (
"errors"
"fmt"
corev1 "k8s.io/api/core/v1"
"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
)
const (
envDotNetCoreClrEnableProfiling = "CORECLR_ENABLE_PROFILING"
envDotNetCoreClrProfiler = "CORECLR_PROFILER"
envDotNetCoreClrProfilerPath = "CORECLR_PROFILER_PATH"
envDotNetAdditionalDeps = "DOTNET_ADDITIONAL_DEPS"
envDotNetSharedStore = "DOTNET_SHARED_STORE"
envDotNetStartupHook = "DOTNET_STARTUP_HOOKS"
envDotNetOTelAutoHome = "OTEL_DOTNET_AUTO_HOME"
dotNetCoreClrEnableProfilingEnabled = "1"
dotNetCoreClrProfilerID = "{918728DD-259F-4A6A-AC2B-B85E1B658318}"
dotNetCoreClrProfilerGlibcPath = "/otel-auto-instrumentation-dotnet/linux-x64/OpenTelemetry.AutoInstrumentation.Native.so"
dotNetCoreClrProfilerMuslPath = "/otel-auto-instrumentation-dotnet/linux-musl-x64/OpenTelemetry.AutoInstrumentation.Native.so"
dotNetAdditionalDepsPath = "/otel-auto-instrumentation-dotnet/AdditionalDeps"
dotNetOTelAutoHomePath = "/otel-auto-instrumentation-dotnet"
dotNetSharedStorePath = "/otel-auto-instrumentation-dotnet/store"
dotNetStartupHookPath = "/otel-auto-instrumentation-dotnet/net/OpenTelemetry.AutoInstrumentation.StartupHook.dll"
dotnetVolumeName = volumeName + "-dotnet"
dotnetInitContainerName = initContainerName + "-dotnet"
dotnetInstrMountPath = "/otel-auto-instrumentation-dotnet"
)
// Supported .NET runtime identifiers (https://learn.microsoft.com/en-us/dotnet/core/rid-catalog), can be set by instrumentation.opentelemetry.io/inject-dotnet.
const (
dotNetRuntimeLinuxGlibc = "linux-x64"
dotNetRuntimeLinuxMusl = "linux-musl-x64"
)
func injectDotNetSDK(dotNetSpec v1alpha1.DotNet, pod corev1.Pod, index int, runtime string) (corev1.Pod, error) {
// caller checks if there is at least one container.
container := &pod.Spec.Containers[index]
err := validateContainerEnv(container.Env, envDotNetStartupHook, envDotNetAdditionalDeps, envDotNetSharedStore)
if err != nil {
return pod, err
}
// check if OTEL_DOTNET_AUTO_HOME env var is already set in the container
// if it is already set, then we assume that .NET Auto-instrumentation is already configured for this container
if getIndexOfEnv(container.Env, envDotNetOTelAutoHome) > -1 {
return pod, errors.New("OTEL_DOTNET_AUTO_HOME environment variable is already set in the container")
}
// check if OTEL_DOTNET_AUTO_HOME env var is already set in the .NET instrumentation spec
// if it is already set, then we assume that .NET Auto-instrumentation is already configured for this container
if getIndexOfEnv(dotNetSpec.Env, envDotNetOTelAutoHome) > -1 {
return pod, errors.New("OTEL_DOTNET_AUTO_HOME environment variable is already set in the .NET instrumentation spec")
}
coreClrProfilerPath := ""
switch runtime {
case "", dotNetRuntimeLinuxGlibc:
coreClrProfilerPath = dotNetCoreClrProfilerGlibcPath
case dotNetRuntimeLinuxMusl:
coreClrProfilerPath = dotNetCoreClrProfilerMuslPath
default:
return pod, fmt.Errorf("provided instrumentation.opentelemetry.io/dotnet-runtime annotation value '%s' is not supported", runtime)
}
// inject .NET instrumentation spec env vars.
for _, env := range dotNetSpec.Env {
idx := getIndexOfEnv(container.Env, env.Name)
if idx == -1 {
container.Env = append(container.Env, env)
}
}
const (
doNotConcatEnvValues = false
concatEnvValues = true
)
setDotNetEnvVar(container, envDotNetCoreClrEnableProfiling, dotNetCoreClrEnableProfilingEnabled, doNotConcatEnvValues)
setDotNetEnvVar(container, envDotNetCoreClrProfiler, dotNetCoreClrProfilerID, doNotConcatEnvValues)
setDotNetEnvVar(container, envDotNetCoreClrProfilerPath, coreClrProfilerPath, doNotConcatEnvValues)
setDotNetEnvVar(container, envDotNetStartupHook, dotNetStartupHookPath, concatEnvValues)
setDotNetEnvVar(container, envDotNetAdditionalDeps, dotNetAdditionalDepsPath, concatEnvValues)
setDotNetEnvVar(container, envDotNetOTelAutoHome, dotNetOTelAutoHomePath, doNotConcatEnvValues)
setDotNetEnvVar(container, envDotNetSharedStore, dotNetSharedStorePath, concatEnvValues)
container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{
Name: dotnetVolumeName,
MountPath: dotnetInstrMountPath,
})
// We just inject Volumes and init containers for the first processed container.
if isInitContainerMissing(pod, dotnetInitContainerName) {
pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{
Name: dotnetVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{
SizeLimit: volumeSize(dotNetSpec.VolumeSizeLimit),
},
}})
pod.Spec.InitContainers = append(pod.Spec.InitContainers, corev1.Container{
Name: dotnetInitContainerName,
Image: dotNetSpec.Image,
Command: []string{"cp", "-r", "/autoinstrumentation/.", dotnetInstrMountPath},
Resources: dotNetSpec.Resources,
VolumeMounts: []corev1.VolumeMount{{
Name: dotnetVolumeName,
MountPath: dotnetInstrMountPath,
}},
})
}
return pod, nil
}
// setDotNetEnvVar function sets env var to the container if not exist already.
// value of concatValues should be set to true if the env var supports multiple values separated by :.
// If it is set to false, the original container's env var value has priority.
func setDotNetEnvVar(container *corev1.Container, envVarName string, envVarValue string, concatValues bool) {
idx := getIndexOfEnv(container.Env, envVarName)
if idx < 0 {
container.Env = append(container.Env, corev1.EnvVar{
Name: envVarName,
Value: envVarValue,
})
return
}
if concatValues {
container.Env[idx].Value = fmt.Sprintf("%s:%s", container.Env[idx].Value, envVarValue)
}
}