From 5ff2a491793b9bfada5b6ad12a77d720959376ee Mon Sep 17 00:00:00 2001 From: cindy-peng Date: Tue, 2 Apr 2024 09:27:58 -0700 Subject: [PATCH 1/6] feat: Add Cloud Run Jobs support --- .../google/cloud/logging/MetadataLoader.java | 379 +++++++------- .../cloud/logging/MonitoredResourceUtil.java | 416 ++++++++------- .../logging/MonitoredResourceUtilTest.java | 493 +++++++++--------- 3 files changed, 677 insertions(+), 611 deletions(-) diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/MetadataLoader.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/MetadataLoader.java index 6553e9039..69f19af05 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/MetadataLoader.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/MetadataLoader.java @@ -20,189 +20,210 @@ import com.google.cloud.logging.MonitoredResourceUtil.Label; import com.google.common.collect.ImmutableMap; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.function.Supplier; public final class MetadataLoader { - public static final String ENV_FLEXIBLE = "flex"; - public static final String ENV_STANDARD = "standard"; - - private final ResourceTypeEnvironmentGetter getter; - - private final ImmutableMap> labelResolvers = - ImmutableMap.>builder() - .put(Label.ClusterName, this::getClusterName) - .put(Label.ConfigurationName, this::getConfigName) - .put(Label.ContainerName, this::getContainerName) - .put(Label.Env, this::getEnv) - .put(Label.FunctionName, this::getFunctionName) - .put(Label.InstanceId, this::getInstanceId) - .put(Label.InstanceName, this::getInstanceName) - .put(Label.CloudRunLocation, this::getCloudRunLocation) - .put(Label.GKELocation, this::getGKELocation) - .put(Label.ModuleId, this::getModuleId) - .put(Label.NamespaceName, this::getNamespaceName) - .put(Label.PodName, this::getPodName) - .put(Label.ProjectId, this::getProjectId) - .put(Label.Region, this::getRegion) - .put(Label.RevisionName, this::getRevisionName) - .put(Label.ServiceName, this::getServiceName) - .put(Label.VersionId, this::getVersionId) - .put(Label.Zone, this::getZone) - .buildOrThrow(); - - public MetadataLoader(ResourceTypeEnvironmentGetter getter) { - this.getter = getter; - } - - /** - * Loads metadata value for the {@code label} argument. - * - * @param label A resource metadata label of type {@see MonitoredResourceUtil.Label} - * @return A string with metadata value or {@code null} if the label is not supported. - */ - public String getValue(MonitoredResourceUtil.Label label) { - Supplier lambda = labelResolvers.get(label); - if (lambda != null) { - return lambda.get(); - } - return null; - } - - private String getClusterName() { - return getter.getAttribute("instance/attributes/cluster-name"); - } - - private String getConfigName() { - return getter.getEnv("K_CONFIGURATION"); - } - - // due to lack of options to discover container name from within process - // allow users to provide the container name via environment variable - private String getContainerName() { - return getter.getEnv("CONTAINER_NAME"); - } - /** - * Distinguish between Standard and Flexible GAE environments. There is no indicator of the - * environment. The path to the startup-script in the metadata attribute was selected as one of - * the new values that explicitly mentioning "flex" and cannot be altered by user (e.g. - * environment variable). The method assumes that the resource type is already identified as - * {@link Resource.AppEngine}. - * - * @return {@link MetadataLoader.ENV_FLEXIBLE} for the Flexible environment and {@link - * MetadataLoader.ENV_STANDARD} for the Standard environment. - */ - private String getEnv() { - String value = getter.getAttribute("instance/attributes/startup-script"); - if ("/var/lib/flex/startup_script.sh".equals(value)) { - return ENV_FLEXIBLE; - } - return ENV_STANDARD; - } - - private String getFunctionName() { - String value = getter.getEnv("K_SERVICE"); - if (value == null) { - // keep supporting custom function name if is not provided by default - // for backward compatibility only; reconsider removing it after Gen2 - // environment is enrolled for Cloud Function - value = getter.getEnv("FUNCTION_NAME"); - } - return value; - } - - private String getInstanceId() { - return getter.getAttribute("instance/id"); - } - - private String getInstanceName() { - return getter.getAttribute("instance/name"); - } - - private String getCloudRunLocation() { - return getRegion(); - } - - private String getGKELocation() { - return getZone(); - } - - private String getModuleId() { - return getter.getEnv("GAE_SERVICE"); - } - /** - * Heuristic to discover the namespace name of the current environment. There is no deterministic - * way to discover the namespace name of the process. The name is read from the {@link - * K8S_POD_NAMESPACE_PATH} when available or read from a user defined environment variable - * "NAMESPACE_NAME" - * - * @return Namespace string or null if the name could not be discovered - */ - private String getNamespaceName() { - String value = null; - try { - value = - new String( - Files.readAllBytes( - Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/namespace")), - UTF_8); - } catch (IOException e) { - // if SA token is not shared the info about namespace is unavailable - // allow users to define the namespace name explicitly - value = getter.getEnv("NAMESPACE_NAME"); - } - return value; - } - // Kubernetes set hostname of the pod to the pod name by default, however hostname can be override - // in manifest - // allow users to provide the container name via environment variable - private String getPodName() { - String value = getter.getEnv("POD_NAME"); - if (value != null) { - return value; - } - return getter.getEnv("HOSTNAME"); - } - - private String getProjectId() { - return getter.getAttribute("project/project-id"); - } - /** - * Retrieves a region from the qualified region of 'projects/[PROJECT_NUMBER]/regions/[REGION]' - * - * @return region string id - */ - private String getRegion() { - String loc = getter.getAttribute("instance/region"); - if (loc != null) { - return loc.substring(loc.lastIndexOf('/') + 1); - } - return null; - } - - private String getRevisionName() { - return getter.getEnv("K_REVISION"); - } - - private String getServiceName() { - return getter.getEnv("K_SERVICE"); - } - - private String getVersionId() { - return getter.getEnv("GAE_VERSION"); - } - /** - * Retrieves a zone from the qualified zone of 'projects/[PROJECT_NUMBER]/zones/[ZONE]' - * - * @return zone string id - */ - private String getZone() { - String loc = getter.getAttribute("instance/zone"); - if (loc != null) { - return loc.substring(loc.lastIndexOf('/') + 1); - } - return null; - } + public static final String ENV_FLEXIBLE = "flex"; + public static final String ENV_STANDARD = "standard"; + + private final ResourceTypeEnvironmentGetter getter; + + private final ImmutableMap> labelResolvers = + ImmutableMap.>builder() + .put(Label.ClusterName, this::getClusterName) + .put(Label.ConfigurationName, this::getConfigName) + .put(Label.ContainerName, this::getContainerName) + .put(Label.Env, this::getEnv) + .put(Label.FunctionName, this::getFunctionName) + .put(Label.InstanceId, this::getInstanceId) + .put(Label.InstanceName, this::getInstanceName) + .put(Label.CloudRunJobName, this::getCloudRunJobName) + .put(Label.CloudRunJobExecutionName, this::getCloudRunJobExecutionName) + .put(Label.CloudRunJobTaskIndex, this::getCloudRunJobTaskIndex) + .put(Label.CloudRunLocation, this::getCloudRunLocation) + .put(Label.GKELocation, this::getGKELocation) + .put(Label.ModuleId, this::getModuleId) + .put(Label.NamespaceName, this::getNamespaceName) + .put(Label.PodName, this::getPodName) + .put(Label.ProjectId, this::getProjectId) + .put(Label.Region, this::getRegion) + .put(Label.RevisionName, this::getRevisionName) + .put(Label.ServiceName, this::getServiceName) + .put(Label.VersionId, this::getVersionId) + .put(Label.Zone, this::getZone) + .buildOrThrow(); + + public MetadataLoader(ResourceTypeEnvironmentGetter getter) { + this.getter = getter; + } + + /** + * Loads metadata value for the {@code label} argument. + * + * @param label A resource metadata label of type {@see MonitoredResourceUtil.Label} + * @return A string with metadata value or {@code null} if the label is not supported. + */ + public String getValue(MonitoredResourceUtil.Label label) { + Supplier lambda = labelResolvers.get(label); + if (lambda != null) { + return lambda.get(); + } + return null; + } + + private String getClusterName() { + return getter.getAttribute("instance/attributes/cluster-name"); + } + + private String getConfigName() { + return getter.getEnv("K_CONFIGURATION"); + } + + // due to lack of options to discover container name from within process + // allow users to provide the container name via environment variable + private String getContainerName() { + return getter.getEnv("CONTAINER_NAME"); + } + + /** + * Distinguish between Standard and Flexible GAE environments. There is no indicator of the + * environment. The path to the startup-script in the metadata attribute was selected as one of + * the new values that explicitly mentioning "flex" and cannot be altered by user (e.g. + * environment variable). The method assumes that the resource type is already identified as + * {@link Resource.AppEngine}. + * + * @return {@link MetadataLoader.ENV_FLEXIBLE} for the Flexible environment and {@link + * MetadataLoader.ENV_STANDARD} for the Standard environment. + */ + private String getEnv() { + String value = getter.getAttribute("instance/attributes/startup-script"); + if ("/var/lib/flex/startup_script.sh".equals(value)) { + return ENV_FLEXIBLE; + } + return ENV_STANDARD; + } + + private String getFunctionName() { + String value = getter.getEnv("K_SERVICE"); + if (value == null) { + // keep supporting custom function name if is not provided by default + // for backward compatibility only; reconsider removing it after Gen2 + // environment is enrolled for Cloud Function + value = getter.getEnv("FUNCTION_NAME"); + } + return value; + } + + private String getInstanceId() { + return getter.getAttribute("instance/id"); + } + + private String getInstanceName() { + return getter.getAttribute("instance/name"); + } + + private String getCloudRunJobName() { + return getter.getEnv("CLOUD_RUN_JOB"); + } + + private String getCloudRunJobExecutionName() { + return getter.getEnv("CLOUD_RUN_EXECUTION"); + } + + private String getCloudRunJobTaskIndex() { + return getter.getEnv("CLOUD_RUN_TASK_INDEX"); + } + + private String getCloudRunLocation() { + return getRegion(); + } + + private String getGKELocation() { + return getZone(); + } + + private String getModuleId() { + return getter.getEnv("GAE_SERVICE"); + } + + /** + * Heuristic to discover the namespace name of the current environment. There is no deterministic + * way to discover the namespace name of the process. The name is read from the {@link + * K8S_POD_NAMESPACE_PATH} when available or read from a user defined environment variable + * "NAMESPACE_NAME" + * + * @return Namespace string or null if the name could not be discovered + */ + private String getNamespaceName() { + String value = null; + try { + value = + new String( + Files.readAllBytes( + Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/namespace")), + UTF_8); + } catch (IOException e) { + // if SA token is not shared the info about namespace is unavailable + // allow users to define the namespace name explicitly + value = getter.getEnv("NAMESPACE_NAME"); + } + return value; + } + + // Kubernetes set hostname of the pod to the pod name by default, however hostname can be override + // in manifest + // allow users to provide the container name via environment variable + private String getPodName() { + String value = getter.getEnv("POD_NAME"); + if (value != null) { + return value; + } + return getter.getEnv("HOSTNAME"); + } + + private String getProjectId() { + return getter.getAttribute("project/project-id"); + } + + /** + * Retrieves a region from the qualified region of 'projects/[PROJECT_NUMBER]/regions/[REGION]' + * + * @return region string id + */ + private String getRegion() { + String loc = getter.getAttribute("instance/region"); + if (loc != null) { + return loc.substring(loc.lastIndexOf('/') + 1); + } + return null; + } + + private String getRevisionName() { + return getter.getEnv("K_REVISION"); + } + + private String getServiceName() { + return getter.getEnv("K_SERVICE"); + } + + private String getVersionId() { + return getter.getEnv("GAE_VERSION"); + } + + /** + * Retrieves a zone from the qualified zone of 'projects/[PROJECT_NUMBER]/zones/[ZONE]' + * + * @return zone string id + */ + private String getZone() { + String loc = getter.getAttribute("instance/zone"); + if (loc != null) { + return loc.substring(loc.lastIndexOf('/') + 1); + } + return null; + } } diff --git a/google-cloud-logging/src/main/java/com/google/cloud/logging/MonitoredResourceUtil.java b/google-cloud-logging/src/main/java/com/google/cloud/logging/MonitoredResourceUtil.java index 1f87e874f..66b02af59 100644 --- a/google-cloud-logging/src/main/java/com/google/cloud/logging/MonitoredResourceUtil.java +++ b/google-cloud-logging/src/main/java/com/google/cloud/logging/MonitoredResourceUtil.java @@ -20,6 +20,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,221 +32,238 @@ */ public class MonitoredResourceUtil { - private static final String APPENGINE_LABEL_PREFIX = "appengine.googleapis.com/"; - protected static final String PORJECTID_LABEL = Label.ProjectId.getKey(); - - protected enum Label { - ClusterName("cluster_name"), - ConfigurationName("configuration_name"), - ContainerName("container_name"), - Env("env"), - FunctionName("function_name"), - InstanceId("instance_id"), - InstanceName("instance_name"), - CloudRunLocation("location"), - GKELocation("location"), - ModuleId("module_id"), - NamespaceName("namespace_name"), - PodName("pod_name"), - ProjectId("project_id"), - Region("region"), - RevisionName("revision_name"), - ServiceName("service_name"), - VersionId("version_id"), - Zone("zone"); - - private final String key; - - Label(String key) { - this.key = key; - } + private static final String APPENGINE_LABEL_PREFIX = "appengine.googleapis.com/"; + private static final String CLOUD_RUN_JOB_LABEL_PREFIX = "run.googleapis.com/"; + protected static final String PORJECTID_LABEL = Label.ProjectId.getKey(); - String getKey() { - return key; - } - } + protected enum Label { + ClusterName("cluster_name"), + ConfigurationName("configuration_name"), + ContainerName("container_name"), + Env("env"), + FunctionName("function_name"), + InstanceId("instance_id"), + InstanceName("instance_name"), + CloudRunJobName("job_name"), + CloudRunJobExecutionName("execution_name"), + CloudRunJobTaskIndex("task_index"), + CloudRunLocation("location"), + GKELocation("location"), + ModuleId("module_id"), + NamespaceName("namespace_name"), + PodName("pod_name"), + ProjectId("project_id"), + Region("region"), + RevisionName("revision_name"), + ServiceName("service_name"), + VersionId("version_id"), + Zone("zone"); - private enum Resource { - CLOUD_RUN("cloud_run_revision"), - CLOUD_FUNCTION("cloud_function"), - APP_ENGINE("gae_app"), - GCE_INSTANCE("gce_instance"), - K8S_CONTAINER("k8s_container"), - GLOBAL("global"); + private final String key; - private final String key; + Label(String key) { + this.key = key; + } - Resource(String key) { - this.key = key; + String getKey() { + return key; + } } - String getKey() { - return key; - } - } - - private static final ImmutableMultimap RESOURCE_TYPE_WITH_LABELS = - ImmutableMultimap.builder() - .putAll(Resource.CLOUD_FUNCTION.getKey(), Label.FunctionName, Label.Region) - .putAll( - Resource.CLOUD_RUN.getKey(), - Label.RevisionName, - Label.ServiceName, - Label.CloudRunLocation, - Label.ConfigurationName) - .putAll( - Resource.APP_ENGINE.getKey(), Label.ModuleId, Label.VersionId, Label.Zone, Label.Env) - .putAll(Resource.GCE_INSTANCE.getKey(), Label.InstanceId, Label.Zone) - .putAll( - Resource.K8S_CONTAINER.getKey(), - Label.GKELocation, - Label.ClusterName, - Label.NamespaceName, - Label.PodName, - Label.ContainerName) - .build(); - - private static final Map cachedMonitoredResources = new HashMap<>(); - private static ResourceTypeEnvironmentGetter getter = new ResourceTypeEnvironmentGetterImpl(); - private static MetadataLoader metadataLoader = new MetadataLoader(getter); - - private MonitoredResourceUtil() {} - - /** - * Method is intended to assist in testing MonitoredResourceUtil class only. - * - * @param getter A mocked environment getter for simulated test environments. - */ - protected static void setEnvironmentGetter(ResourceTypeEnvironmentGetter getter) { - MonitoredResourceUtil.getter = getter; - MonitoredResourceUtil.metadataLoader = new MetadataLoader(getter); - } - - /** - * Build {@link MonitoredResource} based on detected resource type and populate it with labels - * following Monitored Resource Types documentation. - * - * @param projectId A string defining the project id - * @param resourceType A custom resource type - * @return the created {@link MonitoredResource} - * @see Monitored resource Types - */ - public static MonitoredResource getResource(String projectId, String resourceType) { - if (projectId == null || projectId.trim().isEmpty()) { - projectId = metadataLoader.getValue(Label.ProjectId); - } + private enum Resource { + CLOUD_RUN("cloud_run_revision"), + CLOUD_RUN_JOB("cloud_run_job"), + CLOUD_FUNCTION("cloud_function"), + APP_ENGINE("gae_app"), + GCE_INSTANCE("gce_instance"), + K8S_CONTAINER("k8s_container"), + GLOBAL("global"); - MonitoredResource result = cachedMonitoredResources.get(projectId + "/" + resourceType); - if (result != null) { - return result; - } + private final String key; - if (Strings.isNullOrEmpty(resourceType)) { - Resource detectedResourceType = detectResourceType(); - resourceType = detectedResourceType.getKey(); - } - MonitoredResource.Builder builder = - MonitoredResource.newBuilder(resourceType).addLabel(Label.ProjectId.getKey(), projectId); - - for (Label label : RESOURCE_TYPE_WITH_LABELS.get(resourceType)) { - String value = metadataLoader.getValue(label); - if (value != null) { - builder.addLabel(label.getKey(), value); - } - } - result = builder.build(); - cachedMonitoredResources.put(projectId + "/" + resourceType, result); - return result; - } - - /** - * Detect monitored Resource type using the following heuristic rules based on the environment and - * metadata server. - */ - private static Resource detectResourceType() { - // expects supported Google Cloud resource to have access to metadata server - if (getter.getAttribute("") == null) { - return Resource.GLOBAL; - } + Resource(String key) { + this.key = key; + } - if (getter.getEnv("FUNCTION_SIGNATURE_TYPE") != null - && getter.getEnv("FUNCTION_TARGET") != null) { - return Resource.CLOUD_FUNCTION; + String getKey() { + return key; + } } - if (getter.getEnv("K_SERVICE") != null - && getter.getEnv("K_REVISION") != null - && getter.getEnv("K_CONFIGURATION") != null) { - return Resource.CLOUD_RUN; + + private static final ImmutableMultimap RESOURCE_TYPE_WITH_LABELS = + ImmutableMultimap.builder() + .putAll(Resource.CLOUD_FUNCTION.getKey(), Label.FunctionName, Label.Region) + .putAll( + Resource.CLOUD_RUN.getKey(), + Label.RevisionName, + Label.ServiceName, + Label.CloudRunLocation, + Label.ConfigurationName) + .putAll(Resource.CLOUD_RUN_JOB.getKey(), Label.CloudRunJobName, Label.CloudRunLocation) + .putAll( + Resource.APP_ENGINE.getKey(), Label.ModuleId, Label.VersionId, Label.Zone, Label.Env) + .putAll(Resource.GCE_INSTANCE.getKey(), Label.InstanceId, Label.Zone) + .putAll( + Resource.K8S_CONTAINER.getKey(), + Label.GKELocation, + Label.ClusterName, + Label.NamespaceName, + Label.PodName, + Label.ContainerName) + .build(); + + private static final Map cachedMonitoredResources = new HashMap<>(); + private static ResourceTypeEnvironmentGetter getter = new ResourceTypeEnvironmentGetterImpl(); + private static MetadataLoader metadataLoader = new MetadataLoader(getter); + + private MonitoredResourceUtil() { } - if (getter.getEnv("GAE_INSTANCE") != null - && getter.getEnv("GAE_SERVICE") != null - && getter.getEnv("GAE_VERSION") != null) { - return Resource.APP_ENGINE; + + /** + * Method is intended to assist in testing MonitoredResourceUtil class only. + * + * @param getter A mocked environment getter for simulated test environments. + */ + protected static void setEnvironmentGetter(ResourceTypeEnvironmentGetter getter) { + MonitoredResourceUtil.getter = getter; + MonitoredResourceUtil.metadataLoader = new MetadataLoader(getter); } - if (getter.getAttribute("instance/attributes/cluster-name") != null) { - return Resource.K8S_CONTAINER; + + /** + * Build {@link MonitoredResource} based on detected resource type and populate it with labels + * following Monitored Resource Types documentation. + * + * @param projectId A string defining the project id + * @param resourceType A custom resource type + * @return the created {@link MonitoredResource} + * @see Monitored resource Types + */ + public static MonitoredResource getResource(String projectId, String resourceType) { + if (projectId == null || projectId.trim().isEmpty()) { + projectId = metadataLoader.getValue(Label.ProjectId); + } + + MonitoredResource result = cachedMonitoredResources.get(projectId + "/" + resourceType); + if (result != null) { + return result; + } + + if (Strings.isNullOrEmpty(resourceType)) { + Resource detectedResourceType = detectResourceType(); + resourceType = detectedResourceType.getKey(); + } + MonitoredResource.Builder builder = + MonitoredResource.newBuilder(resourceType).addLabel(Label.ProjectId.getKey(), projectId); + + for (Label label : RESOURCE_TYPE_WITH_LABELS.get(resourceType)) { + String value = metadataLoader.getValue(label); + if (value != null) { + builder.addLabel(label.getKey(), value); + } + } + result = builder.build(); + cachedMonitoredResources.put(projectId + "/" + resourceType, result); + return result; } - if (getter.getAttribute("instance/preempted") != null - && getter.getAttribute("instance/cpu-platform") != null - && getter.getAttribute("instance/attributes/gae_app_bucket") == null) { - return Resource.GCE_INSTANCE; + + /** + * Detect monitored Resource type using the following heuristic rules based on the environment and + * metadata server. + */ + private static Resource detectResourceType() { + // expects supported Google Cloud resource to have access to metadata server + if (getter.getAttribute("") == null) { + return Resource.GLOBAL; + } + + if (getter.getEnv("FUNCTION_SIGNATURE_TYPE") != null + && getter.getEnv("FUNCTION_TARGET") != null) { + return Resource.CLOUD_FUNCTION; + } + if (getter.getEnv("K_SERVICE") != null + && getter.getEnv("K_REVISION") != null + && getter.getEnv("K_CONFIGURATION") != null) { + return Resource.CLOUD_RUN; + } + if (getter.getEnv("CLOUD_RUN_JOB") != null + && getter.getEnv("CLOUD_RUN_EXECUTION") != null + && getter.getEnv("CLOUD_RUN_TASK_INDEX") != null) { + return Resource.CLOUD_RUN_JOB; + } + if (getter.getEnv("GAE_INSTANCE") != null + && getter.getEnv("GAE_SERVICE") != null + && getter.getEnv("GAE_VERSION") != null) { + return Resource.APP_ENGINE; + } + if (getter.getAttribute("instance/attributes/cluster-name") != null) { + return Resource.K8S_CONTAINER; + } + if (getter.getAttribute("instance/preempted") != null + && getter.getAttribute("instance/cpu-platform") != null + && getter.getAttribute("instance/attributes/gae_app_bucket") == null) { + return Resource.GCE_INSTANCE; + } + // other Google Cloud resources (e.g. CloudBuild) might be misdetected + return Resource.GLOBAL; } - // other Google Cloud resources (e.g. CloudBuild) might be misdetected - return Resource.GLOBAL; - } - - /** - * Returns custom log entry enhancers (if available) for resource type. - * - * @return custom log entry enhancers - */ - public static List getResourceEnhancers() { - Resource resourceType = detectResourceType(); - return createEnhancers(resourceType); - } - - private static List createEnhancers(Resource resourceType) { - List enhancers = new ArrayList<>(2); - if (resourceType == Resource.APP_ENGINE) { - enhancers.add(new TraceLoggingEnhancer(APPENGINE_LABEL_PREFIX)); - if (MetadataLoader.ENV_FLEXIBLE.equals(metadataLoader.getValue(Label.Env))) { - enhancers.add( - new LabelLoggingEnhancer(APPENGINE_LABEL_PREFIX, ImmutableList.of(Label.InstanceName))); - } + + /** + * Returns custom log entry enhancers (if available) for resource type. + * + * @return custom log entry enhancers + */ + public static List getResourceEnhancers() { + Resource resourceType = detectResourceType(); + return createEnhancers(resourceType); } - return enhancers; - } - - /** - * Adds additional resource-based labels to log entries. Labels that can be provided with {@link - * MonitoredResource.Builder#addLabel(String, String)} are restricted to a supported set per - * resource. - * - * @see Logging Labels - */ - private static class LabelLoggingEnhancer implements LoggingEnhancer { - - private final Map labels; - - LabelLoggingEnhancer(String prefix, List