Skip to content

Commit 39dd9b5

Browse files
Support DotNet auto-instrumentation (open-telemetry#976)
* Adds support for dotnet auto-instrumentation * changes default image for testing * adds dotnet auto-instrumentation to the ldflags in makefile * changes in Makefile * fixes issue in makefile * fixes issue in dockerfile * passes dotnet sample app image to e2e test * fixes version in the dot net autoinstrumentation version file * adds testing changes for dot-net-autoinstrumentation * fixes annotation * downloads dot-net release from github * removes git push condition check * removes git push condition check * changes repo to logicmonitor * adds dontnet auto-instrumentation related details in readme * adds docker image layer caching in github action * triggers action on pull request * adds e2e test cases for dotnet instrumentation * fixes version for dotnet instrumentation * version changes * restores clusterversion file * restores changes in Makefile * minor change * Adds configuration details to dockerfile * updates version of dotnet auto-instrumentation * changes env var name from OTEL_DOTNET_TRACER_INSTRUMENTATIONS to OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS * removes java related env variables * fixes e2e test cases * fixes e2e test case * deletes .DS_Store file * sets OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS to default value * fixes e2e test case * fixes e2e test case
1 parent 5aea4e1 commit 39dd9b5

35 files changed

+1741
-12
lines changed

.github/workflows/publish-autoinstrumentation-dotnet.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ jobs:
6262
tags: ${{ steps.meta.outputs.tags }}
6363
labels: ${{ steps.meta.outputs.labels }}
6464
cache-from: type=local,src=/tmp/.buildx-cache
65-
cache-to: type=local,dest=/tmp/.buildx-cache
65+
cache-to: type=local,dest=/tmp/.buildx-cache

Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ ARG TARGETALLOCATOR_VERSION
2525
ARG AUTO_INSTRUMENTATION_JAVA_VERSION
2626
ARG AUTO_INSTRUMENTATION_NODEJS_VERSION
2727
ARG AUTO_INSTRUMENTATION_PYTHON_VERSION
28+
ARG AUTO_INSTRUMENTATION_DOTNET_VERSION
2829

2930
# Build
30-
RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -ldflags="-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION}" -a -o manager main.go
31+
RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -ldflags="-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION} -X ${VERSION_PKG}.autoInstrumentationDotNet=${AUTO_INSTRUMENTATION_DOTNET_VERSION}" -a -o manager main.go
3132

3233
# Use distroless as minimal base image to package the manager binary
3334
# Refer to https://github.com/GoogleContainerTools/distroless for more details

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ TARGETALLOCATOR_VERSION ?= "$(shell grep -v '\#' versions.txt | grep targetalloc
88
AUTO_INSTRUMENTATION_JAVA_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-java | awk -F= '{print $$2}')"
99
AUTO_INSTRUMENTATION_NODEJS_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-nodejs | awk -F= '{print $$2}')"
1010
AUTO_INSTRUMENTATION_PYTHON_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-python | awk -F= '{print $$2}')"
11-
LD_FLAGS ?= "-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION}"
11+
AUTO_INSTRUMENTATION_DOTNET_VERSION ?= "$(shell grep -v '\#' versions.txt | grep autoinstrumentation-dotnet | awk -F= '{print $$2}')"
12+
LD_FLAGS ?= "-X ${VERSION_PKG}.version=${VERSION} -X ${VERSION_PKG}.buildDate=${VERSION_DATE} -X ${VERSION_PKG}.otelCol=${OTELCOL_VERSION} -X ${VERSION_PKG}.targetAllocator=${TARGETALLOCATOR_VERSION} -X ${VERSION_PKG}.autoInstrumentationJava=${AUTO_INSTRUMENTATION_JAVA_VERSION} -X ${VERSION_PKG}.autoInstrumentationNodeJS=${AUTO_INSTRUMENTATION_NODEJS_VERSION} -X ${VERSION_PKG}.autoInstrumentationPython=${AUTO_INSTRUMENTATION_PYTHON_VERSION} -X ${VERSION_PKG}.autoInstrumentationDotNet=${AUTO_INSTRUMENTATION_DOTNET_VERSION}"
1213

1314
# Image URL to use all building/pushing image targets
1415
IMG_PREFIX ?= ghcr.io/${USER}/opentelemetry-operator
@@ -174,7 +175,7 @@ set-test-image-vars:
174175
# Build the container image, used only for local dev purposes
175176
.PHONY: container
176177
container:
177-
docker build -t ${IMG} --build-arg VERSION_PKG=${VERSION_PKG} --build-arg VERSION=${VERSION} --build-arg VERSION_DATE=${VERSION_DATE} --build-arg OTELCOL_VERSION=${OTELCOL_VERSION} --build-arg TARGETALLOCATOR_VERSION=${TARGETALLOCATOR_VERSION} --build-arg AUTO_INSTRUMENTATION_JAVA_VERSION=${AUTO_INSTRUMENTATION_JAVA_VERSION} --build-arg AUTO_INSTRUMENTATION_NODEJS_VERSION=${AUTO_INSTRUMENTATION_NODEJS_VERSION} --build-arg AUTO_INSTRUMENTATION_PYTHON_VERSION=${AUTO_INSTRUMENTATION_PYTHON_VERSION} .
178+
docker build -t ${IMG} --build-arg VERSION_PKG=${VERSION_PKG} --build-arg VERSION=${VERSION} --build-arg VERSION_DATE=${VERSION_DATE} --build-arg OTELCOL_VERSION=${OTELCOL_VERSION} --build-arg TARGETALLOCATOR_VERSION=${TARGETALLOCATOR_VERSION} --build-arg AUTO_INSTRUMENTATION_JAVA_VERSION=${AUTO_INSTRUMENTATION_JAVA_VERSION} --build-arg AUTO_INSTRUMENTATION_NODEJS_VERSION=${AUTO_INSTRUMENTATION_NODEJS_VERSION} --build-arg AUTO_INSTRUMENTATION_PYTHON_VERSION=${AUTO_INSTRUMENTATION_PYTHON_VERSION} --build-arg AUTO_INSTRUMENTATION_DOTNET_VERSION=${AUTO_INSTRUMENTATION_DOTNET_VERSION} .
178179

179180
# Push the container image, used only for local dev purposes
180181
.PHONY: container-push

README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ When using sidecar mode the OpenTelemetry collector container will have the envi
166166

167167
### OpenTelemetry auto-instrumentation injection
168168

169-
The operator can inject and configure OpenTelemetry auto-instrumentation libraries. Currently Java, NodeJS and Python are supported.
169+
The operator can inject and configure OpenTelemetry auto-instrumentation libraries. Currently DotNet, Java, NodeJS and Python are supported.
170170

171171
To use auto-instrumentation, configure an `Instrumentation` resource with the configuration for the SDK and instrumentation.
172172

@@ -210,12 +210,20 @@ Python:
210210
instrumentation.opentelemetry.io/inject-python: "true"
211211
```
212212

213+
DotNet:
214+
```bash
215+
instrumentation.opentelemetry.io/inject-dotnet: "true"
216+
```
217+
213218
The possible values for the annotation can be
214219
* `"true"` - inject and `Instrumentation` resource from the namespace.
215220
* `"my-instrumentation"` - name of `Instrumentation` CR instance in the current namespace.
216221
* `"my-other-namespace/my-instrumentation"` - name and namespace of `Instrumentation` CR instance in another namespace.
217222
* `"false"` - do not inject
218223

224+
225+
>**Note:** For `DotNet` auto-instrumentation, by default, operator sets the `OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS` environment variable which specifies the list of traces source instrumentations you want to enable. The value that is set by default by the operator is all available instrumentations supported by the `openTelemery-dotnet-instrumentation` release consumed in the image, i.e. `AspNet,HttpClient,SqlClient`. This value can be overriden by configuring the environment variable explicitely.
226+
219227
#### Multi-container pods
220228

221229
If nothing else is specified, instrumentation is performed on the first container available in the pod spec.
@@ -271,6 +279,8 @@ spec:
271279
image: your-customized-auto-instrumentation-image:nodejs
272280
python:
273281
image: your-customized-auto-instrumentation-image:python
282+
dotnet:
283+
image: your-customized-auto-instrumentation-image:dotnet
274284
```
275285

276286
The Dockerfiles for auto-instrumentation can be found in [autoinstrumentation directory](./autoinstrumentation).

apis/v1alpha1/instrumentation_types.go

+16
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ type InstrumentationSpec struct {
5454
// Python defines configuration for python auto-instrumentation.
5555
// +optional
5656
Python Python `json:"python,omitempty"`
57+
58+
// DotNet defines configuration for DotNet auto-instrumentation.
59+
// +optional
60+
DotNet DotNet `json:"dotnet,omitempty"`
5761
}
5862

5963
// Resource defines the configuration for the resource attributes, as defined by the OpenTelemetry specification.
@@ -129,6 +133,18 @@ type Python struct {
129133
Env []corev1.EnvVar `json:"env,omitempty"`
130134
}
131135

136+
type DotNet struct {
137+
// Image is a container image with DotNet SDK and auto-instrumentation.
138+
// +optional
139+
Image string `json:"image,omitempty"`
140+
141+
// Env defines DotNet specific env vars. There are four layers for env vars' definitions and
142+
// the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`.
143+
// If the former var had been defined, then the other vars would be ignored.
144+
// +optional
145+
Env []corev1.EnvVar `json:"env,omitempty"`
146+
}
147+
132148
// InstrumentationStatus defines status of the instrumentation.
133149
type InstrumentationStatus struct {
134150
}

apis/v1alpha1/instrumentation_webhook.go

+32-5
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ import (
2727
)
2828

2929
const (
30-
AnnotationDefaultAutoInstrumentationJava = "instrumentation.opentelemetry.io/default-auto-instrumentation-java-image"
31-
AnnotationDefaultAutoInstrumentationNodeJS = "instrumentation.opentelemetry.io/default-auto-instrumentation-nodejs-image"
32-
AnnotationDefaultAutoInstrumentationPython = "instrumentation.opentelemetry.io/default-auto-instrumentation-python-image"
33-
envPrefix = "OTEL_"
34-
envSplunkPrefix = "SPLUNK_"
30+
AnnotationDefaultAutoInstrumentationJava = "instrumentation.opentelemetry.io/default-auto-instrumentation-java-image"
31+
AnnotationDefaultAutoInstrumentationNodeJS = "instrumentation.opentelemetry.io/default-auto-instrumentation-nodejs-image"
32+
AnnotationDefaultAutoInstrumentationPython = "instrumentation.opentelemetry.io/default-auto-instrumentation-python-image"
33+
AnnotationDefaultAutoInstrumentationDotNet = "instrumentation.opentelemetry.io/default-auto-instrumentation-dotnet-image"
34+
envPrefix = "OTEL_"
35+
envSplunkPrefix = "SPLUNK_"
36+
envOtelDotnetAutoTracesEnabledInstrumentations = "OTEL_DOTNET_AUTO_TRACES_ENABLED_INSTRUMENTATIONS"
37+
defaultEnabledTracesInstrumentations = "AspNet,HttpClient,SqlClient"
3538
)
3639

3740
// log is for logging in this package.
@@ -72,6 +75,18 @@ func (r *Instrumentation) Default() {
7275
r.Spec.Python.Image = val
7376
}
7477
}
78+
if r.Spec.DotNet.Image == "" {
79+
if val, ok := r.Annotations[AnnotationDefaultAutoInstrumentationDotNet]; ok {
80+
r.Spec.DotNet.Image = val
81+
}
82+
}
83+
// by default set all the available instrumentations for dotnet unless the env is already set
84+
if !r.isEnvVarSet(envOtelDotnetAutoTracesEnabledInstrumentations) {
85+
r.Spec.DotNet.Env = append(r.Spec.DotNet.Env, corev1.EnvVar{
86+
Name: envOtelDotnetAutoTracesEnabledInstrumentations,
87+
Value: defaultEnabledTracesInstrumentations,
88+
})
89+
}
7590
}
7691

7792
// +kubebuilder:webhook:verbs=create;update,path=/validate-opentelemetry-io-v1alpha1-instrumentation,mutating=false,failurePolicy=fail,groups=opentelemetry.io,resources=instrumentations,versions=v1alpha1,name=vinstrumentationcreateupdate.kb.io,sideEffects=none,admissionReviewVersions=v1
@@ -125,6 +140,9 @@ func (in *Instrumentation) validate() error {
125140
if err := in.validateEnv(in.Spec.Python.Env); err != nil {
126141
return err
127142
}
143+
if err := in.validateEnv(in.Spec.DotNet.Env); err != nil {
144+
return err
145+
}
128146

129147
return nil
130148
}
@@ -137,3 +155,12 @@ func (in *Instrumentation) validateEnv(envs []corev1.EnvVar) error {
137155
}
138156
return nil
139157
}
158+
159+
func (in *Instrumentation) isEnvVarSet(name string) bool {
160+
for _, env := range in.Spec.DotNet.Env {
161+
if env.Name == name {
162+
return true
163+
}
164+
}
165+
return false
166+
}

apis/v1alpha1/instrumentation_webhook_test.go

+34
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"testing"
1919

2020
"github.com/stretchr/testify/assert"
21+
v1 "k8s.io/api/core/v1"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223
)
2324

@@ -28,13 +29,46 @@ func TestInstrumentationDefaultingWebhook(t *testing.T) {
2829
AnnotationDefaultAutoInstrumentationJava: "java-img:1",
2930
AnnotationDefaultAutoInstrumentationNodeJS: "nodejs-img:1",
3031
AnnotationDefaultAutoInstrumentationPython: "python-img:1",
32+
AnnotationDefaultAutoInstrumentationDotNet: "dotnet-img:1",
3133
},
3234
},
3335
}
3436
inst.Default()
3537
assert.Equal(t, "java-img:1", inst.Spec.Java.Image)
3638
assert.Equal(t, "nodejs-img:1", inst.Spec.NodeJS.Image)
3739
assert.Equal(t, "python-img:1", inst.Spec.Python.Image)
40+
assert.Equal(t, "dotnet-img:1", inst.Spec.DotNet.Image)
41+
assert.Equal(t, true, inst.isEnvVarSet(envOtelDotnetAutoTracesEnabledInstrumentations))
42+
}
43+
44+
func TestInstrumentationDefaultingWebhookOtelDotNetTracesEnabledInstruEnvSet(t *testing.T) {
45+
inst := &Instrumentation{
46+
ObjectMeta: metav1.ObjectMeta{
47+
Annotations: map[string]string{
48+
AnnotationDefaultAutoInstrumentationJava: "java-img:1",
49+
AnnotationDefaultAutoInstrumentationNodeJS: "nodejs-img:1",
50+
AnnotationDefaultAutoInstrumentationPython: "python-img:1",
51+
AnnotationDefaultAutoInstrumentationDotNet: "dotnet-img:1",
52+
},
53+
},
54+
Spec: InstrumentationSpec{
55+
DotNet: DotNet{
56+
Env: []v1.EnvVar{
57+
{
58+
Name: envOtelDotnetAutoTracesEnabledInstrumentations,
59+
Value: "AspNet,HttpClient",
60+
},
61+
},
62+
},
63+
},
64+
}
65+
inst.Default()
66+
for _, env := range inst.Spec.DotNet.Env {
67+
if env.Name == envOtelDotnetAutoTracesEnabledInstrumentations {
68+
assert.Equal(t, "AspNet,HttpClient", env.Value)
69+
break
70+
}
71+
}
3872
}
3973

4074
func TestInstrumentationValidatingWebhook(t *testing.T) {

apis/v1alpha1/zz_generated.deepcopy.go

+23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)