...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package resource
16
17 import (
18 "bufio"
19 "context"
20 "errors"
21 "io"
22 "os"
23 "regexp"
24
25 semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
26 )
27
28 type containerIDProvider func() (string, error)
29
30 var (
31 containerID containerIDProvider = getContainerIDFromCGroup
32 cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]+)(?:\.|\s*$)`)
33 )
34
35 type cgroupContainerIDDetector struct{}
36
37 const cgroupPath = "/proc/self/cgroup"
38
39
40
41 func (cgroupContainerIDDetector) Detect(ctx context.Context) (*Resource, error) {
42 containerID, err := containerID()
43 if err != nil {
44 return nil, err
45 }
46
47 if containerID == "" {
48 return Empty(), nil
49 }
50 return NewWithAttributes(semconv.SchemaURL, semconv.ContainerID(containerID)), nil
51 }
52
53 var (
54 defaultOSStat = os.Stat
55 osStat = defaultOSStat
56
57 defaultOSOpen = func(name string) (io.ReadCloser, error) {
58 return os.Open(name)
59 }
60 osOpen = defaultOSOpen
61 )
62
63
64
65 func getContainerIDFromCGroup() (string, error) {
66 if _, err := osStat(cgroupPath); errors.Is(err, os.ErrNotExist) {
67
68 return "", nil
69 }
70
71 file, err := osOpen(cgroupPath)
72 if err != nil {
73 return "", err
74 }
75 defer file.Close()
76
77 return getContainerIDFromReader(file), nil
78 }
79
80
81 func getContainerIDFromReader(reader io.Reader) string {
82 scanner := bufio.NewScanner(reader)
83 for scanner.Scan() {
84 line := scanner.Text()
85
86 if id := getContainerIDFromLine(line); id != "" {
87 return id
88 }
89 }
90 return ""
91 }
92
93
94 func getContainerIDFromLine(line string) string {
95 matches := cgroupContainerIDRe.FindStringSubmatch(line)
96 if len(matches) <= 1 {
97 return ""
98 }
99 return matches[1]
100 }
101
View as plain text