Skip to content

Commit 81a32db

Browse files
author
Israel Blancas
authored
Merge branch 'main' into feat/3090
2 parents 27b380e + e82f595 commit 81a32db

20 files changed

+720
-46
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
change_type: enhancement
2+
3+
component: auto-instrumentation
4+
5+
note: Add support for k8s labels such as app.kubernetes.io/name for resource attributes
6+
7+
issues: [3112]
8+
9+
subtext: |
10+
You can opt-in as follows:
11+
```yaml
12+
apiVersion: opentelemetry.io/v1alpha1
13+
kind: Instrumentation
14+
metadata:
15+
name: my-instrumentation
16+
spec:
17+
defaults:
18+
useLabelsForResourceAttributes: true
19+
```
20+
The following labels are supported:
21+
- `app.kubernetes.io/name` becomes `service.name`
22+
- `app.kubernetes.io/version` becomes `service.version`
23+
- `app.kubernetes.io/part-of` becomes `service.namespace`
24+
- `app.kubernetes.io/instance` becomes `service.instance.id`

README.md

+56-2
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,9 @@ spec:
717717
EOF
718718
```
719719

720-
### Setting instrumentation resource attributes via namespace annotations
720+
## Configure resource attributes
721+
722+
### Configure resource attributes with annotations
721723

722724
This example shows a pod configuration with OpenTelemetry annotations using the `resource.opentelemetry.io/` prefix. These annotations can be used to add resource attributes to data produced by OpenTelemetry instrumentation.
723725

@@ -734,7 +736,59 @@ spec:
734736
containers:
735737
- name: main-container
736738
image: your-image:tag
737-
```
739+
```
740+
741+
### Configure resource attributes with labels
742+
743+
You can also use common labels to set resource attributes.
744+
745+
The following labels are supported:
746+
- `app.kubernetes.io/name` becomes `service.name`
747+
- `app.kubernetes.io/version` becomes `service.version`
748+
- `app.kubernetes.io/part-of` becomes `service.namespace`
749+
- `app.kubernetes.io/instance` becomes `service.instance.id`
750+
751+
```yaml
752+
apiVersion: v1
753+
kind: Pod
754+
metadata:
755+
name: example-pod
756+
labels:
757+
app.kubernetes.io/name: "my-service"
758+
app.kubernetes.io/version: "1.0.0"
759+
app.kubernetes.io/part-of: "shop"
760+
app.kubernetes.io/instance: "my-service-123"
761+
spec:
762+
containers:
763+
- name: main-container
764+
image: your-image:tag
765+
```
766+
767+
This requires an explicit opt-in as follows:
768+
769+
```yaml
770+
apiVersion: opentelemetry.io/v1alpha1
771+
kind: Instrumentation
772+
metadata:
773+
name: my-instrumentation
774+
spec:
775+
defaults:
776+
useLabelsForResourceAttributes: true
777+
```
778+
779+
### Priority for setting resource attributes
780+
781+
The priority for setting resource attributes is as follows (first found wins):
782+
783+
1. Resource attributes set via `OTEL_RESOURCE_ATTRIBUTES` and `OTEL_SERVICE_NAME` environment variables
784+
2. Resource attributes set via annotations (with the `resource.opentelemetry.io/` prefix)
785+
3. Resource attributes set via labels (e.g. `app.kubernetes.io/name`)
786+
if the `Instrumentation` CR has defaults.useLabelsForResourceAttributes=true (see above)
787+
4. Resource attributes calculated from the pod's metadata (e.g. `k8s.pod.name`)
788+
5. Resource attributes set via the `Instrumentation` CR (in the `spec.resource.resourceAttributes` section)
789+
790+
This priority is applied for each resource attribute separately, so it is possible to set some attributes via
791+
annotations and others via labels.
738792

739793
## Compatibility matrix
740794

apis/v1alpha1/instrumentation_types.go

+13
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ type InstrumentationSpec struct {
4040
// +optional
4141
Sampler `json:"sampler,omitempty"`
4242

43+
// Defaults defines default values for the instrumentation.
44+
Defaults Defaults `json:"defaults,omitempty"`
45+
4346
// Env defines common env vars. There are four layers for env vars' definitions and
4447
// the precedence order is: `original container env vars` > `language specific env vars` > `common env vars` > `instrument spec configs' vars`.
4548
// If the former var had been defined, then the other vars would be ignored.
@@ -114,6 +117,16 @@ type Sampler struct {
114117
Argument string `json:"argument,omitempty"`
115118
}
116119

120+
// Defaults defines default values for the instrumentation.
121+
type Defaults struct {
122+
// UseLabelsForResourceAttributes defines whether to use common labels for resource attributes:
123+
// - `app.kubernetes.io/name` becomes `service.name`
124+
// - `app.kubernetes.io/version` becomes `service.version`
125+
// - `app.kubernetes.io/part-of` becomes `service.namespace`
126+
// - `app.kubernetes.io/instance` becomes `service.instance.id`
127+
UseLabelsForResourceAttributes bool `json:"useLabelsForResourceAttributes,omitempty"`
128+
}
129+
117130
// Java defines Java SDK and instrumentation configuration.
118131
type Java struct {
119132
// Image is a container image with javaagent auto-instrumentation JAR.

apis/v1alpha1/zz_generated.deepcopy.go

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

bundle/community/manifests/opentelemetry.io_instrumentations.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ spec:
224224
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
225225
x-kubernetes-int-or-string: true
226226
type: object
227+
defaults:
228+
properties:
229+
useLabelsForResourceAttributes:
230+
type: boolean
231+
type: object
227232
dotnet:
228233
properties:
229234
env:

bundle/openshift/manifests/opentelemetry.io_instrumentations.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ spec:
224224
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
225225
x-kubernetes-int-or-string: true
226226
type: object
227+
defaults:
228+
properties:
229+
useLabelsForResourceAttributes:
230+
type: boolean
231+
type: object
227232
dotnet:
228233
properties:
229234
env:

config/crd/bases/opentelemetry.io_instrumentations.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ spec:
222222
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
223223
x-kubernetes-int-or-string: true
224224
type: object
225+
defaults:
226+
properties:
227+
useLabelsForResourceAttributes:
228+
type: boolean
229+
type: object
225230
dotnet:
226231
properties:
227232
env:

docs/api.md

+38
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ InstrumentationSpec defines the desired state of OpenTelemetry SDK and instrumen
9595
ApacheHttpd defines configuration for Apache HTTPD auto-instrumentation.<br/>
9696
</td>
9797
<td>false</td>
98+
</tr><tr>
99+
<td><b><a href="#instrumentationspecdefaults">defaults</a></b></td>
100+
<td>object</td>
101+
<td>
102+
Defaults defines default values for the instrumentation.<br/>
103+
</td>
104+
<td>false</td>
98105
</tr><tr>
99106
<td><b><a href="#instrumentationspecdotnet">dotnet</a></b></td>
100107
<td>object</td>
@@ -887,6 +894,37 @@ only the result of this request.<br/>
887894
</table>
888895

889896

897+
### Instrumentation.spec.defaults
898+
<sup><sup>[↩ Parent](#instrumentationspec)</sup></sup>
899+
900+
901+
902+
Defaults defines default values for the instrumentation.
903+
904+
<table>
905+
<thead>
906+
<tr>
907+
<th>Name</th>
908+
<th>Type</th>
909+
<th>Description</th>
910+
<th>Required</th>
911+
</tr>
912+
</thead>
913+
<tbody><tr>
914+
<td><b>useLabelsForResourceAttributes</b></td>
915+
<td>boolean</td>
916+
<td>
917+
UseLabelsForResourceAttributes defines whether to use common labels for resource attributes:
918+
- `app.kubernetes.io/name` becomes `service.name`
919+
- `app.kubernetes.io/version` becomes `service.version`
920+
- `app.kubernetes.io/part-of` becomes `service.namespace`
921+
- `app.kubernetes.io/instance` becomes `service.instance.id`<br/>
922+
</td>
923+
<td>false</td>
924+
</tr></tbody>
925+
</table>
926+
927+
890928
### Instrumentation.spec.dotnet
891929
<sup><sup>[↩ Parent](#instrumentationspec)</sup></sup>
892930

pkg/constants/env.go

+12-6
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ const (
3131
AnnotationDefaultAutoInstrumentationApacheHttpd = InstrumentationPrefix + "default-auto-instrumentation-apache-httpd-image"
3232
AnnotationDefaultAutoInstrumentationNginx = InstrumentationPrefix + "default-auto-instrumentation-nginx-image"
3333

34-
EnvPodName = "OTEL_RESOURCE_ATTRIBUTES_POD_NAME"
35-
EnvPodUID = "OTEL_RESOURCE_ATTRIBUTES_POD_UID"
36-
EnvPodIP = "OTEL_POD_IP"
37-
EnvNodeName = "OTEL_RESOURCE_ATTRIBUTES_NODE_NAME"
38-
EnvNodeIP = "OTEL_NODE_IP"
39-
OtelAnnotationNamespace = "resource.opentelemetry.io/"
34+
LabelAppName = "app.kubernetes.io/name"
35+
LabelAppInstance = "app.kubernetes.io/instance"
36+
LabelAppVersion = "app.kubernetes.io/version"
37+
LabelAppPartOf = "app.kubernetes.io/part-of"
38+
39+
ResourceAttributeAnnotationPrefix = "resource.opentelemetry.io/"
40+
41+
EnvPodName = "OTEL_RESOURCE_ATTRIBUTES_POD_NAME"
42+
EnvPodUID = "OTEL_RESOURCE_ATTRIBUTES_POD_UID"
43+
EnvPodIP = "OTEL_POD_IP"
44+
EnvNodeName = "OTEL_RESOURCE_ATTRIBUTES_NODE_NAME"
45+
EnvNodeIP = "OTEL_NODE_IP"
4046

4147
FlagCRMetrics = "enable-cr-metrics"
4248
FlagApacheHttpd = "enable-apache-httpd-instrumentation"

pkg/instrumentation/apachehttpd.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const (
5959
6) Inject mounting of volumes / files into appropriate directories in application container
6060
*/
6161

62-
func injectApacheHttpdagent(_ logr.Logger, apacheSpec v1alpha1.ApacheHttpd, pod corev1.Pod, index int, otlpEndpoint string, resourceMap map[string]string) corev1.Pod {
62+
func injectApacheHttpdagent(_ logr.Logger, apacheSpec v1alpha1.ApacheHttpd, pod corev1.Pod, useLabelsForResourceAttributes bool, index int, otlpEndpoint string, resourceMap map[string]string) corev1.Pod {
6363

6464
// caller checks if there is at least one container
6565
container := &pod.Spec.Containers[index]
@@ -162,7 +162,7 @@ func injectApacheHttpdagent(_ logr.Logger, apacheSpec v1alpha1.ApacheHttpd, pod
162162
Env: []corev1.EnvVar{
163163
{
164164
Name: apacheAttributesEnvVar,
165-
Value: getApacheOtelConfig(pod, apacheSpec, index, otlpEndpoint, resourceMap),
165+
Value: getApacheOtelConfig(pod, useLabelsForResourceAttributes, apacheSpec, index, otlpEndpoint, resourceMap),
166166
},
167167
{Name: apacheServiceInstanceIdEnvVar,
168168
ValueFrom: &corev1.EnvVarSource{
@@ -201,7 +201,7 @@ func isApacheInitContainerMissing(pod corev1.Pod, containerName string) bool {
201201

202202
// Calculate Apache HTTPD agent configuration file based on attributes provided by the injection rules
203203
// and by the pod values.
204-
func getApacheOtelConfig(pod corev1.Pod, apacheSpec v1alpha1.ApacheHttpd, index int, otelEndpoint string, resourceMap map[string]string) string {
204+
func getApacheOtelConfig(pod corev1.Pod, useLabelsForResourceAttributes bool, apacheSpec v1alpha1.ApacheHttpd, index int, otelEndpoint string, resourceMap map[string]string) string {
205205
template := `
206206
#Load the Otel Webserver SDK
207207
LoadFile %[1]s/sdk_lib/lib/libopentelemetry_common.so
@@ -222,7 +222,7 @@ LoadModule otel_apache_module %[1]s/WebServerModule/Apache/libmod_apache_otel%[2
222222
if otelEndpoint == "" {
223223
otelEndpoint = "http://localhost:4317/"
224224
}
225-
serviceName := chooseServiceName(pod, resourceMap, index)
225+
serviceName := chooseServiceName(pod, useLabelsForResourceAttributes, resourceMap, index)
226226
serviceNamespace := pod.GetNamespace()
227227
if len(serviceNamespace) == 0 {
228228
serviceNamespace = resourceMap[string(semconv.K8SNamespaceNameKey)]

pkg/instrumentation/apachehttpd_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ func TestInjectApacheHttpdagent(t *testing.T) {
417417

418418
for _, test := range tests {
419419
t.Run(test.name, func(t *testing.T) {
420-
pod := injectApacheHttpdagent(logr.Discard(), test.ApacheHttpd, test.pod, 0, "http://otlp-endpoint:4317", resourceMap)
420+
pod := injectApacheHttpdagent(logr.Discard(), test.ApacheHttpd, test.pod, false, 0, "http://otlp-endpoint:4317", resourceMap)
421421
assert.Equal(t, test.expected, pod)
422422
})
423423
}
@@ -527,7 +527,7 @@ func TestInjectApacheHttpdagentUnknownNamespace(t *testing.T) {
527527

528528
for _, test := range tests {
529529
t.Run(test.name, func(t *testing.T) {
530-
pod := injectApacheHttpdagent(logr.Discard(), test.ApacheHttpd, test.pod, 0, "http://otlp-endpoint:4317", resourceMap)
530+
pod := injectApacheHttpdagent(logr.Discard(), test.ApacheHttpd, test.pod, false, 0, "http://otlp-endpoint:4317", resourceMap)
531531
assert.Equal(t, test.expected, pod)
532532
})
533533
}

pkg/instrumentation/nginx.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const (
6262
6) Inject mounting of volumes / files into appropriate directories in the application container
6363
*/
6464

65-
func injectNginxSDK(_ logr.Logger, nginxSpec v1alpha1.Nginx, pod corev1.Pod, index int, otlpEndpoint string, resourceMap map[string]string) corev1.Pod {
65+
func injectNginxSDK(_ logr.Logger, nginxSpec v1alpha1.Nginx, pod corev1.Pod, useLabelsForResourceAttributes bool, index int, otlpEndpoint string, resourceMap map[string]string) corev1.Pod {
6666

6767
// caller checks if there is at least one container
6868
container := &pod.Spec.Containers[index]
@@ -217,7 +217,7 @@ mv ${NGINX_AGENT_CONF_DIR_FULL}/opentelemetry_agent.conf ${NGINX_AGENT_CONF_DIR
217217
Env: []corev1.EnvVar{
218218
{
219219
Name: nginxAttributesEnvVar,
220-
Value: getNginxOtelConfig(pod, nginxSpec, index, otlpEndpoint, resourceMap),
220+
Value: getNginxOtelConfig(pod, useLabelsForResourceAttributes, nginxSpec, index, otlpEndpoint, resourceMap),
221221
},
222222
{
223223
Name: "OTEL_NGINX_I13N_SCRIPT",
@@ -277,12 +277,12 @@ func isNginxInitContainerMissing(pod corev1.Pod, containerName string) bool {
277277

278278
// Calculate Nginx agent configuration file based on attributes provided by the injection rules
279279
// and by the pod values.
280-
func getNginxOtelConfig(pod corev1.Pod, nginxSpec v1alpha1.Nginx, index int, otelEndpoint string, resourceMap map[string]string) string {
280+
func getNginxOtelConfig(pod corev1.Pod, useLabelsForResourceAttributes bool, nginxSpec v1alpha1.Nginx, index int, otelEndpoint string, resourceMap map[string]string) string {
281281

282282
if otelEndpoint == "" {
283283
otelEndpoint = "http://localhost:4317/"
284284
}
285-
serviceName := chooseServiceName(pod, resourceMap, index)
285+
serviceName := chooseServiceName(pod, useLabelsForResourceAttributes, resourceMap, index)
286286
serviceNamespace := pod.GetNamespace()
287287
if len(serviceNamespace) == 0 {
288288
serviceNamespace = resourceMap[string(semconv.K8SNamespaceNameKey)]

pkg/instrumentation/nginx_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ func TestInjectNginxSDK(t *testing.T) {
477477

478478
for _, test := range tests {
479479
t.Run(test.name, func(t *testing.T) {
480-
pod := injectNginxSDK(logr.Discard(), test.Nginx, test.pod, 0, "http://otlp-endpoint:4317", resourceMap)
480+
pod := injectNginxSDK(logr.Discard(), test.Nginx, test.pod, false, 0, "http://otlp-endpoint:4317", resourceMap)
481481
assert.Equal(t, test.expected, pod)
482482
})
483483
}
@@ -600,7 +600,7 @@ func TestInjectNginxUnknownNamespace(t *testing.T) {
600600

601601
for _, test := range tests {
602602
t.Run(test.name, func(t *testing.T) {
603-
pod := injectNginxSDK(logr.Discard(), test.Nginx, test.pod, 0, "http://otlp-endpoint:4317", resourceMap)
603+
pod := injectNginxSDK(logr.Discard(), test.Nginx, test.pod, false, 0, "http://otlp-endpoint:4317", resourceMap)
604604
assert.Equal(t, test.expected, pod)
605605
})
606606
}

0 commit comments

Comments
 (0)