blob: 0d8619715e62266af22caa05968e7a599dfe42e8 [file] [log] [blame]
Abhay Kumar40252eb2025-10-13 13:25:53 +00001// Copyright The OpenTelemetry Authors
2// SPDX-License-Identifier: Apache-2.0
3
4package resource // import "go.opentelemetry.io/otel/sdk/resource"
5
6import (
7 "bufio"
8 "context"
9 "errors"
10 "io"
11 "os"
12 "regexp"
13
14 semconv "go.opentelemetry.io/otel/semconv/v1.34.0"
15)
16
17type containerIDProvider func() (string, error)
18
19var (
20 containerID containerIDProvider = getContainerIDFromCGroup
21 cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*[-:])?([0-9a-f]+)(?:\.|\s*$)`)
22)
23
24type cgroupContainerIDDetector struct{}
25
26const cgroupPath = "/proc/self/cgroup"
27
28// Detect returns a *Resource that describes the id of the container.
29// If no container id found, an empty resource will be returned.
30func (cgroupContainerIDDetector) Detect(ctx context.Context) (*Resource, error) {
31 containerID, err := containerID()
32 if err != nil {
33 return nil, err
34 }
35
36 if containerID == "" {
37 return Empty(), nil
38 }
39 return NewWithAttributes(semconv.SchemaURL, semconv.ContainerID(containerID)), nil
40}
41
42var (
43 defaultOSStat = os.Stat
44 osStat = defaultOSStat
45
46 defaultOSOpen = func(name string) (io.ReadCloser, error) {
47 return os.Open(name)
48 }
49 osOpen = defaultOSOpen
50)
51
52// getContainerIDFromCGroup returns the id of the container from the cgroup file.
53// If no container id found, an empty string will be returned.
54func getContainerIDFromCGroup() (string, error) {
55 if _, err := osStat(cgroupPath); errors.Is(err, os.ErrNotExist) {
56 // File does not exist, skip
57 return "", nil
58 }
59
60 file, err := osOpen(cgroupPath)
61 if err != nil {
62 return "", err
63 }
64 defer file.Close()
65
66 return getContainerIDFromReader(file), nil
67}
68
69// getContainerIDFromReader returns the id of the container from reader.
70func getContainerIDFromReader(reader io.Reader) string {
71 scanner := bufio.NewScanner(reader)
72 for scanner.Scan() {
73 line := scanner.Text()
74
75 if id := getContainerIDFromLine(line); id != "" {
76 return id
77 }
78 }
79 return ""
80}
81
82// getContainerIDFromLine returns the id of the container from one string line.
83func getContainerIDFromLine(line string) string {
84 matches := cgroupContainerIDRe.FindStringSubmatch(line)
85 if len(matches) <= 1 {
86 return ""
87 }
88 return matches[1]
89}