@@ -9,6 +9,7 @@ package vxray
9
9
10
10
import (
11
11
"fmt"
12
+ "os"
12
13
13
14
"github.com/aws/aws-xray-sdk-go/awsplugins/beanstalk"
14
15
"github.com/aws/aws-xray-sdk-go/awsplugins/ec2"
@@ -18,15 +19,18 @@ import (
18
19
"v.io/v23/context"
19
20
"v.io/v23/logging"
20
21
"v.io/v23/vtrace"
22
+ "v.io/x/ref/lib/aws/vxray/internal"
21
23
"v.io/x/ref/lib/flags"
22
24
libvtrace "v.io/x/ref/lib/vtrace"
23
25
)
24
26
25
27
type options struct {
26
- mergeLogging bool
27
- mapToHTTP bool
28
- newStore bool
29
- newStoreFlags flags.VtraceFlags
28
+ mergeLogging bool
29
+ mapToHTTP bool
30
+ newStore bool
31
+ newStoreFlags flags.VtraceFlags
32
+ configMap , configMapKey string
33
+ containerized bool
30
34
}
31
35
32
36
// Option represents an option to InitXRay.
@@ -53,6 +57,44 @@ func BeanstalkPlugin() Option {
53
57
}
54
58
}
55
59
60
+ // KubernetesCluster configures obtaining information about the process'
61
+ // current environment when running under Kubernetes (k8s), whether managed by
62
+ // AWS EKS or any other control plane implementation. It requires that the
63
+ // K8S configuration creates a configmap that contains the cluster name.
64
+ // The configMap argument names that configmap and configMapKey
65
+ // is the key in that configmap for the cluster name. For example, when using
66
+ // the AWS cloudwatch/insights/xray-daemon daemonset the values for those
67
+ // would be:
68
+ // /api/v1/namespaces/amazon-cloudwatch/configmaps/cluster-info
69
+ // cluster.name
70
+ //
71
+ // When configured, xray segments will contain a 'cluster_name' annotation.
72
+ func KubernetesCluster (configMap , configMapKey string ) Option {
73
+ return func (o * options ) {
74
+ o .configMap , o .configMapKey = configMap , configMapKey
75
+ }
76
+ }
77
+
78
+ // EKSCluster calls KubernetesCluster with the values commonly used
79
+ // with EKS clusters.
80
+ func EKSCluster () Option {
81
+ return KubernetesCluster ("/api/v1/namespaces/amazon-cloudwatch/configmaps/cluster-info" , "cluster.name" )
82
+ }
83
+
84
+ // ContainerIDAndHost requests that container id and host information be
85
+ // obtained and added to traces. The container id is obtained by parsing
86
+ // the /proc/self/cgroup file, and the host by call the operating system's
87
+ // hostname function. When running under kubernetes for example, a pod's
88
+ // name is configured as its hostname.
89
+ //
90
+ // When configured, xray segments will contain 'container_id' and 'container_host'
91
+ // annotations.
92
+ func ContainerIDAndHost () Option {
93
+ return func (o * options ) {
94
+ o .containerized = true
95
+ }
96
+ }
97
+
56
98
// MergeLogging arrays for xray logging messages to be merged with vanadium
57
99
// log messages.
58
100
func MergeLogging (v bool ) Option {
@@ -105,44 +147,73 @@ func (xl *xraylogger) Log(level xraylog.LogLevel, msg fmt.Stringer) {
105
147
}
106
148
}
107
149
108
- func initXRay (ctx * context.T , config xray.Config , opts []Option ) (* context.T , * options , error ) {
109
- o := & options {mapToHTTP : true }
110
- for _ , fn := range opts {
111
- fn (o )
112
- }
150
+ func (m * manager ) initXRay (ctx * context.T , config xray.Config ) (* context.T , error ) {
113
151
if err := xray .Configure (config ); err != nil {
114
152
ctx .Errorf ("failed to configure xray context: %v" , err )
115
- return ctx , nil , err
153
+ return ctx , err
116
154
}
117
- if o .mergeLogging {
155
+ if m . options .mergeLogging {
118
156
xray .SetLogger (& xraylogger {context .LoggerFromContext (ctx )})
119
157
}
120
158
ctx , err := WithConfig (ctx , config )
121
- return ctx , o , err
159
+ return ctx , err
122
160
}
123
161
124
162
// InitXRay configures the AWS xray service and returns a context containing
125
163
// the xray configuration. This should only be called once. The vflags argument
126
164
// is used solely to check if xray tracing is enabled and not to create a
127
- // new vtrace.Store, if a new store is required, the
165
+ // new vtrace.Store, if a new/alternate store is required, the WithNewStore option
166
+ // should be used to specify the store to be used.
128
167
func InitXRay (ctx * context.T , vflags flags.VtraceFlags , config xray.Config , opts ... Option ) (* context.T , error ) {
129
168
if ! vflags .EnableAWSXRay {
130
169
return ctx , nil
131
170
}
132
171
octx := ctx
133
- ctx , options , err := initXRay (ctx , config , opts )
172
+ mgr := & manager {}
173
+ mgr .options .mapToHTTP = true
174
+ for _ , fn := range opts {
175
+ fn (& mgr .options )
176
+ }
177
+ ctx , err := mgr .initXRay (ctx , config )
134
178
if err != nil {
135
179
return octx , err
136
180
}
137
-
138
- if options .newStore {
139
- store , err := libvtrace .NewStore (options .newStoreFlags )
181
+ if mgr .options .newStore {
182
+ store , err := libvtrace .NewStore (mgr .options .newStoreFlags )
140
183
if err != nil {
141
184
return octx , err
142
185
}
143
186
ctx = vtrace .WithStore (ctx , store )
144
187
}
145
- mgr := & manager {mapToHTTP : options .mapToHTTP }
188
+ if mgr .options .containerized {
189
+ if hostNameErr == nil {
190
+ mgr .containerHost = hostName
191
+ } else {
192
+ ctx .Infof ("failed to obtain host name from: %v" , hostNameErr )
193
+ }
194
+ cgroupFile := "/proc/self/cgroup"
195
+ if cid , err := internal .GetContainerID (cgroupFile ); err == nil {
196
+ mgr .containerID = cid
197
+ } else {
198
+ ctx .Infof ("failed to obtain container id" , err )
199
+ }
200
+ }
201
+ if cm := mgr .options .configMap ; len (cm ) > 0 {
202
+ if clusterName , err := internal .GetEKSClusterName (ctx , cm , mgr .options .configMapKey ); err == nil {
203
+ mgr .clusterName = clusterName
204
+ } else {
205
+ ctx .Infof ("failed to obtain cluster name from %v.%v: %v" , cm , mgr .options .configMapKey , err )
206
+ }
207
+ }
146
208
ctx = vtrace .WithManager (ctx , mgr )
147
209
return ctx , nil
148
210
}
211
+
212
+ var (
213
+ hostName string
214
+ hostNameErr error
215
+ )
216
+
217
+ func init () {
218
+ hostName , hostNameErr = os .Hostname ()
219
+ }
0 commit comments