mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
269 lines
7.1 KiB
Go
269 lines
7.1 KiB
Go
|
// Copyright 2021 Google LLC
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
package logging
|
||
|
|
||
|
import (
|
||
|
"io/ioutil"
|
||
|
"os"
|
||
|
"strings"
|
||
|
"sync"
|
||
|
|
||
|
"cloud.google.com/go/compute/metadata"
|
||
|
mrpb "google.golang.org/genproto/googleapis/api/monitoredres"
|
||
|
)
|
||
|
|
||
|
// CommonResource sets the monitored resource associated with all log entries
|
||
|
// written from a Logger. If not provided, the resource is automatically
|
||
|
// detected based on the running environment (on GCE, GCR, GCF and GAE Standard only).
|
||
|
// This value can be overridden per-entry by setting an Entry's Resource field.
|
||
|
func CommonResource(r *mrpb.MonitoredResource) LoggerOption { return commonResource{r} }
|
||
|
|
||
|
type commonResource struct{ *mrpb.MonitoredResource }
|
||
|
|
||
|
func (r commonResource) set(l *Logger) { l.commonResource = r.MonitoredResource }
|
||
|
|
||
|
var detectedResource struct {
|
||
|
pb *mrpb.MonitoredResource
|
||
|
once sync.Once
|
||
|
}
|
||
|
|
||
|
// isAppEngine returns true for both standard and flex
|
||
|
func isAppEngine() bool {
|
||
|
_, service := os.LookupEnv("GAE_SERVICE")
|
||
|
_, version := os.LookupEnv("GAE_VERSION")
|
||
|
_, instance := os.LookupEnv("GAE_INSTANCE")
|
||
|
|
||
|
return service && version && instance
|
||
|
}
|
||
|
|
||
|
func detectAppEngineResource() *mrpb.MonitoredResource {
|
||
|
projectID, err := metadata.ProjectID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
if projectID == "" {
|
||
|
projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")
|
||
|
}
|
||
|
zone, err := metadata.Zone()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "gae_app",
|
||
|
Labels: map[string]string{
|
||
|
"project_id": projectID,
|
||
|
"module_id": os.Getenv("GAE_SERVICE"),
|
||
|
"version_id": os.Getenv("GAE_VERSION"),
|
||
|
"instance_id": os.Getenv("GAE_INSTANCE"),
|
||
|
"runtime": os.Getenv("GAE_RUNTIME"),
|
||
|
"zone": zone,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func isCloudFunction() bool {
|
||
|
// Reserved envvars in older function runtimes, e.g. Node.js 8, Python 3.7 and Go 1.11.
|
||
|
_, name := os.LookupEnv("FUNCTION_NAME")
|
||
|
_, region := os.LookupEnv("FUNCTION_REGION")
|
||
|
_, entry := os.LookupEnv("ENTRY_POINT")
|
||
|
|
||
|
// Reserved envvars in newer function runtimes.
|
||
|
_, target := os.LookupEnv("FUNCTION_TARGET")
|
||
|
_, signature := os.LookupEnv("FUNCTION_SIGNATURE_TYPE")
|
||
|
_, service := os.LookupEnv("K_SERVICE")
|
||
|
return (name && region && entry) || (target && signature && service)
|
||
|
}
|
||
|
|
||
|
func detectCloudFunction() *mrpb.MonitoredResource {
|
||
|
projectID, err := metadata.ProjectID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
zone, err := metadata.Zone()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
// Newer functions runtimes store name in K_SERVICE.
|
||
|
functionName, exists := os.LookupEnv("K_SERVICE")
|
||
|
if !exists {
|
||
|
functionName, _ = os.LookupEnv("FUNCTION_NAME")
|
||
|
}
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "cloud_function",
|
||
|
Labels: map[string]string{
|
||
|
"project_id": projectID,
|
||
|
"region": regionFromZone(zone),
|
||
|
"function_name": functionName,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func isCloudRun() bool {
|
||
|
_, config := os.LookupEnv("K_CONFIGURATION")
|
||
|
_, service := os.LookupEnv("K_SERVICE")
|
||
|
_, revision := os.LookupEnv("K_REVISION")
|
||
|
return config && service && revision
|
||
|
}
|
||
|
|
||
|
func detectCloudRunResource() *mrpb.MonitoredResource {
|
||
|
projectID, err := metadata.ProjectID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
zone, err := metadata.Zone()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "cloud_run_revision",
|
||
|
Labels: map[string]string{
|
||
|
"project_id": projectID,
|
||
|
"location": regionFromZone(zone),
|
||
|
"service_name": os.Getenv("K_SERVICE"),
|
||
|
"revision_name": os.Getenv("K_REVISION"),
|
||
|
"configuration_name": os.Getenv("K_CONFIGURATION"),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func isKubernetesEngine() bool {
|
||
|
clusterName, err := metadata.InstanceAttributeValue("cluster-name")
|
||
|
// Note: InstanceAttributeValue can return "", nil
|
||
|
if err != nil || clusterName == "" {
|
||
|
return false
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func detectKubernetesResource() *mrpb.MonitoredResource {
|
||
|
projectID, err := metadata.ProjectID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
zone, err := metadata.Zone()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
clusterName, err := metadata.InstanceAttributeValue("cluster-name")
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
namespaceBytes, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
|
||
|
namespaceName := ""
|
||
|
if err == nil {
|
||
|
namespaceName = string(namespaceBytes)
|
||
|
}
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "k8s_container",
|
||
|
Labels: map[string]string{
|
||
|
"cluster_name": clusterName,
|
||
|
"location": zone,
|
||
|
"project_id": projectID,
|
||
|
"pod_name": os.Getenv("HOSTNAME"),
|
||
|
"namespace_name": namespaceName,
|
||
|
// To get the `container_name` label, users need to explicitly provide it.
|
||
|
"container_name": os.Getenv("CONTAINER_NAME"),
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func detectGCEResource() *mrpb.MonitoredResource {
|
||
|
projectID, err := metadata.ProjectID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
id, err := metadata.InstanceID()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
zone, err := metadata.Zone()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
name, err := metadata.InstanceName()
|
||
|
if err != nil {
|
||
|
return nil
|
||
|
}
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "gce_instance",
|
||
|
Labels: map[string]string{
|
||
|
"project_id": projectID,
|
||
|
"instance_id": id,
|
||
|
"instance_name": name,
|
||
|
"zone": zone,
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func detectResource() *mrpb.MonitoredResource {
|
||
|
detectedResource.once.Do(func() {
|
||
|
switch {
|
||
|
// AppEngine, Functions, CloudRun, Kubernetes are detected first,
|
||
|
// as metadata.OnGCE() erroneously returns true on these runtimes.
|
||
|
case isAppEngine():
|
||
|
detectedResource.pb = detectAppEngineResource()
|
||
|
case isCloudFunction():
|
||
|
detectedResource.pb = detectCloudFunction()
|
||
|
case isCloudRun():
|
||
|
detectedResource.pb = detectCloudRunResource()
|
||
|
case isKubernetesEngine():
|
||
|
detectedResource.pb = detectKubernetesResource()
|
||
|
case metadata.OnGCE():
|
||
|
detectedResource.pb = detectGCEResource()
|
||
|
}
|
||
|
})
|
||
|
return detectedResource.pb
|
||
|
}
|
||
|
|
||
|
var resourceInfo = map[string]struct{ rtype, label string }{
|
||
|
"organizations": {"organization", "organization_id"},
|
||
|
"folders": {"folder", "folder_id"},
|
||
|
"projects": {"project", "project_id"},
|
||
|
"billingAccounts": {"billing_account", "account_id"},
|
||
|
}
|
||
|
|
||
|
func monitoredResource(parent string) *mrpb.MonitoredResource {
|
||
|
parts := strings.SplitN(parent, "/", 2)
|
||
|
if len(parts) != 2 {
|
||
|
return globalResource(parent)
|
||
|
}
|
||
|
info, ok := resourceInfo[parts[0]]
|
||
|
if !ok {
|
||
|
return globalResource(parts[1])
|
||
|
}
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: info.rtype,
|
||
|
Labels: map[string]string{info.label: parts[1]},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func regionFromZone(zone string) string {
|
||
|
cutoff := strings.LastIndex(zone, "-")
|
||
|
if cutoff > 0 {
|
||
|
return zone[:cutoff]
|
||
|
}
|
||
|
return zone
|
||
|
}
|
||
|
|
||
|
func globalResource(projectID string) *mrpb.MonitoredResource {
|
||
|
return &mrpb.MonitoredResource{
|
||
|
Type: "global",
|
||
|
Labels: map[string]string{
|
||
|
"project_id": projectID,
|
||
|
},
|
||
|
}
|
||
|
}
|