1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package logging
16
17 import (
18 "runtime"
19 "strings"
20 "sync"
21
22 "cloud.google.com/go/logging/internal"
23 mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
24 )
25
26
27
28
29
30 func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} }
31
32 type commonResource struct{ *mrpb.MonitoredResource }
33
34 func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource }
35
36 type resource struct {
37 pb *mrpb.MonitoredResource
38 attrs internal.ResourceAttributesGetter
39 once *sync.Once
40 }
41
42 var detectedResource = &resource{
43 attrs: internal.ResourceAttributes(),
44 once: new(sync.Once),
45 }
46
47 func (r *resource) metadataProjectID() string {
48 return r.attrs.Metadata("project/project-id")
49 }
50
51 func (r *resource) metadataZone() string {
52 zone := r.attrs.Metadata("instance/zone")
53 if zone != "" {
54 return zone[strings.LastIndex(zone, "/")+1:]
55 }
56 return ""
57 }
58
59 func (r *resource) metadataRegion() string {
60 region := r.attrs.Metadata("instance/region")
61 if region != "" {
62 return region[strings.LastIndex(region, "/")+1:]
63 }
64 return ""
65 }
66
67
68 func (r *resource) isMetadataActive() bool {
69 data := r.attrs.Metadata("")
70 return data != ""
71 }
72
73
74 func (r *resource) isAppEngine() bool {
75 service := r.attrs.EnvVar("GAE_SERVICE")
76 version := r.attrs.EnvVar("GAE_VERSION")
77 instance := r.attrs.EnvVar("GAE_INSTANCE")
78 return service != "" && version != "" && instance != ""
79 }
80
81 func detectAppEngineResource() *mrpb.MonitoredResource {
82 projectID := detectedResource.metadataProjectID()
83 if projectID == "" {
84 projectID = detectedResource.attrs.EnvVar("GOOGLE_CLOUD_PROJECT")
85 }
86 if projectID == "" {
87 return nil
88 }
89 zone := detectedResource.metadataZone()
90 service := detectedResource.attrs.EnvVar("GAE_SERVICE")
91 version := detectedResource.attrs.EnvVar("GAE_VERSION")
92
93 return &mrpb.MonitoredResource{
94 Type: "gae_app",
95 Labels: map[string]string{
96 "project_id": projectID,
97 "module_id": service,
98 "version_id": version,
99 "zone": zone,
100 },
101 }
102 }
103
104 func (r *resource) isCloudFunction() bool {
105 target := r.attrs.EnvVar("FUNCTION_TARGET")
106 signature := r.attrs.EnvVar("FUNCTION_SIGNATURE_TYPE")
107
108 service := r.attrs.EnvVar("K_SERVICE")
109 return target != "" && signature != "" && service != ""
110 }
111
112 func detectCloudFunction() *mrpb.MonitoredResource {
113 projectID := detectedResource.metadataProjectID()
114 if projectID == "" {
115 return nil
116 }
117 region := detectedResource.metadataRegion()
118 functionName := detectedResource.attrs.EnvVar("K_SERVICE")
119 return &mrpb.MonitoredResource{
120 Type: "cloud_function",
121 Labels: map[string]string{
122 "project_id": projectID,
123 "region": region,
124 "function_name": functionName,
125 },
126 }
127 }
128
129 func (r *resource) isCloudRunService() bool {
130 config := r.attrs.EnvVar("K_CONFIGURATION")
131
132 service := r.attrs.EnvVar("K_SERVICE")
133 revision := r.attrs.EnvVar("K_REVISION")
134 return config != "" && service != "" && revision != ""
135 }
136
137 func (r *resource) isCloudRunJob() bool {
138 if r.attrs.EnvVar("CLOUD_RUN_JOB") == "" {
139 return false
140 }
141 if r.attrs.EnvVar("CLOUD_RUN_EXECUTION") == "" {
142 return false
143 }
144 if r.attrs.EnvVar("CLOUD_RUN_TASK_INDEX") == "" {
145 return false
146 }
147 if r.attrs.EnvVar("CLOUD_RUN_TASK_ATTEMPT") == "" {
148 return false
149 }
150 return true
151 }
152
153 func detectCloudRunServiceResource() *mrpb.MonitoredResource {
154 projectID := detectedResource.metadataProjectID()
155 if projectID == "" {
156 return nil
157 }
158 region := detectedResource.metadataRegion()
159 config := detectedResource.attrs.EnvVar("K_CONFIGURATION")
160 service := detectedResource.attrs.EnvVar("K_SERVICE")
161 revision := detectedResource.attrs.EnvVar("K_REVISION")
162 return &mrpb.MonitoredResource{
163 Type: "cloud_run_revision",
164 Labels: map[string]string{
165 "project_id": projectID,
166 "location": region,
167 "service_name": service,
168 "revision_name": revision,
169 "configuration_name": config,
170 },
171 }
172 }
173
174 func detectCloudRunJobResource() *mrpb.MonitoredResource {
175 projectID := detectedResource.metadataProjectID()
176 if projectID == "" {
177 return nil
178 }
179 region := detectedResource.metadataRegion()
180 job := detectedResource.attrs.EnvVar("CLOUD_RUN_JOB")
181 return &mrpb.MonitoredResource{
182 Type: "cloud_run_job",
183 Labels: map[string]string{
184 "project_id": projectID,
185 "location": region,
186 "job_name": job,
187 },
188 }
189 }
190
191 func (r *resource) isKubernetesEngine() bool {
192 clusterName := r.attrs.Metadata("instance/attributes/cluster-name")
193 if clusterName == "" {
194 return false
195 }
196 return true
197 }
198
199 func detectKubernetesResource() *mrpb.MonitoredResource {
200 projectID := detectedResource.metadataProjectID()
201 if projectID == "" {
202 return nil
203 }
204 clusterName := detectedResource.attrs.Metadata("instance/attributes/cluster-name")
205 clusterLocation := detectedResource.attrs.Metadata("instance/attributes/cluster-location")
206 namespaceName := detectedResource.attrs.ReadAll("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
207 if namespaceName == "" {
208
209
210 namespaceName = detectedResource.attrs.EnvVar("NAMESPACE_NAME")
211 }
212
213 podName := detectedResource.attrs.EnvVar("HOSTNAME")
214
215 containerName := detectedResource.attrs.EnvVar("CONTAINER_NAME")
216 return &mrpb.MonitoredResource{
217 Type: "k8s_container",
218 Labels: map[string]string{
219 "cluster_name": clusterName,
220 "location": clusterLocation,
221 "project_id": projectID,
222 "pod_name": podName,
223 "namespace_name": namespaceName,
224 "container_name": containerName,
225 },
226 }
227 }
228
229 func (r *resource) isComputeEngine() bool {
230 preempted := r.attrs.Metadata("instance/preempted")
231 platform := r.attrs.Metadata("instance/cpu-platform")
232 appBucket := r.attrs.Metadata("instance/attributes/gae_app_bucket")
233 return preempted != "" && platform != "" && appBucket == ""
234 }
235
236 func detectComputeEngineResource() *mrpb.MonitoredResource {
237 projectID := detectedResource.metadataProjectID()
238 if projectID == "" {
239 return nil
240 }
241 id := detectedResource.attrs.Metadata("instance/id")
242 zone := detectedResource.metadataZone()
243 return &mrpb.MonitoredResource{
244 Type: "gce_instance",
245 Labels: map[string]string{
246 "project_id": projectID,
247 "instance_id": id,
248 "zone": zone,
249 },
250 }
251 }
252
253 func detectResource() *mrpb.MonitoredResource {
254 detectedResource.once.Do(func() {
255 if detectedResource.isMetadataActive() {
256 name := systemProductName()
257 switch {
258 case name == "Google App Engine", detectedResource.isAppEngine():
259 detectedResource.pb = detectAppEngineResource()
260 case name == "Google Cloud Functions", detectedResource.isCloudFunction():
261 detectedResource.pb = detectCloudFunction()
262
263
264 case detectedResource.isCloudRunService():
265 detectedResource.pb = detectCloudRunServiceResource()
266 case detectedResource.isCloudRunJob():
267 detectedResource.pb = detectCloudRunJobResource()
268
269
270 case detectedResource.isKubernetesEngine():
271 detectedResource.pb = detectKubernetesResource()
272 case detectedResource.isComputeEngine():
273 detectedResource.pb = detectComputeEngineResource()
274 }
275 }
276 })
277 return detectedResource.pb
278 }
279
280
281
282 func systemProductName() string {
283 if runtime.GOOS != "linux" {
284
285 return ""
286 }
287 slurp := detectedResource.attrs.ReadAll("/sys/class/dmi/id/product_name")
288 return strings.TrimSpace(slurp)
289 }
290
291 var resourceInfo = map[string]struct{ rtype, label string }{
292 "organizations": {"organization", "organization_id"},
293 "folders": {"folder", "folder_id"},
294 "projects": {"project", "project_id"},
295 "billingAccounts": {"billing_account", "account_id"},
296 }
297
298 func monitoredResource(parent string) *mrpb.MonitoredResource {
299 parts := strings.SplitN(parent, "/", 2)
300 if len(parts) != 2 {
301 return globalResource(parent)
302 }
303 info, ok := resourceInfo[parts[0]]
304 if !ok {
305 return globalResource(parts[1])
306 }
307 return &mrpb.MonitoredResource{
308 Type: info.rtype,
309 Labels: map[string]string{info.label: parts[1]},
310 }
311 }
312
313 func globalResource(projectID string) *mrpb.MonitoredResource {
314 return &mrpb.MonitoredResource{
315 Type: "global",
316 Labels: map[string]string{
317 "project_id": projectID,
318 },
319 }
320 }
321
View as plain text