Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(logging): correctly detect GKE resource #4092

Merged
merged 11 commits into from May 19, 2021
202 changes: 0 additions & 202 deletions logging/logging.go
Expand Up @@ -32,15 +32,13 @@ import (
"fmt"
"log"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"
"unicode/utf8"

"cloud.google.com/go/compute/metadata"
"cloud.google.com/go/internal/version"
vkit "cloud.google.com/go/logging/apiv2"
"cloud.google.com/go/logging/internal"
Expand Down Expand Up @@ -242,206 +240,6 @@ type LoggerOption interface {
set(*Logger)
}

// 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
}

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 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 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,
},
}
}

// 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 detectResource() *mrpb.MonitoredResource {
detectedResource.once.Do(func() {
switch {
// AppEngine, Functions, CloudRun 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 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,
},
}
}

// CommonLabels are labels that apply to all log entries written from a Logger,
// so that you don't have to repeat them in each log entry's Labels field. If
// any of the log entries contains a (key, value) with the same key that is in
Expand Down