gcp-o11y: Remove monitored resource detection for logging (#10020)

* removed populating monitored resource to k8s_conatiner by default for logging; Delegating the resource detection to cloud logging library instead (enabled by default)

* remove kubernetes resource detection logic from observability
This commit is contained in:
DNVindhya 2023-04-06 11:48:46 -07:00 committed by GitHub
parent 18e274de65
commit cc6be5f8c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 18 additions and 487 deletions

View File

@ -90,12 +90,10 @@ public final class GcpObservability implements AutoCloseable {
*/ */
public static synchronized GcpObservability grpcInit() throws IOException { public static synchronized GcpObservability grpcInit() throws IOException {
if (instance == null) { if (instance == null) {
GlobalLocationTags globalLocationTags = new GlobalLocationTags();
ObservabilityConfigImpl observabilityConfig = ObservabilityConfigImpl.getInstance(); ObservabilityConfigImpl observabilityConfig = ObservabilityConfigImpl.getInstance();
TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper( TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(
observabilityConfig.getProjectId()); observabilityConfig.getProjectId());
Sink sink = new GcpLogSink(observabilityConfig.getProjectId(), Sink sink = new GcpLogSink(observabilityConfig.getProjectId(), observabilityConfig,
globalLocationTags.getLocationTags(), observabilityConfig,
SERVICES_TO_EXCLUDE, traceLoggingHelper); SERVICES_TO_EXCLUDE, traceLoggingHelper);
LogHelper helper = new LogHelper(sink); LogHelper helper = new LogHelper(sink);
ConfigFilterHelper configFilterHelper = ConfigFilterHelper.getInstance(observabilityConfig); ConfigFilterHelper configFilterHelper = ConfigFilterHelper.getInstance(observabilityConfig);

View File

@ -1,148 +0,0 @@
/*
* Copyright 2022 The gRPC Authors
*
* 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 io.grpc.gcp.observability;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.util.Strings;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Scanner;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
/** A container of all global location tags used for observability. */
final class GlobalLocationTags {
private static final Logger logger = Logger.getLogger(GlobalLocationTags.class.getName());
private final Map<String, String> locationTags;
GlobalLocationTags() {
ImmutableMap.Builder<String, String> locationTagsBuilder = ImmutableMap.builder();
populate(locationTagsBuilder);
locationTags = locationTagsBuilder.buildOrThrow();
}
private static String applyTrim(String value) {
if (!Strings.isNullOrEmpty(value)) {
value = value.trim();
}
return value;
}
Map<String, String> getLocationTags() {
return locationTags;
}
@VisibleForTesting
static void populateFromMetadataServer(ImmutableMap.Builder<String, String> locationTags) {
MetadataConfig metadataConfig = new MetadataConfig(new DefaultHttpTransportFactory());
metadataConfig.init();
locationTags.putAll(metadataConfig.getAllValues());
}
@VisibleForTesting
static void populateFromKubernetesValues(ImmutableMap.Builder<String, String> locationTags,
String namespaceFile,
String hostnameFile, String cgroupFile) {
// namespace name: contents of file /var/run/secrets/kubernetes.io/serviceaccount/namespace
populateFromFileContents(locationTags, "namespace_name",
namespaceFile, GlobalLocationTags::applyTrim);
// pod_name: hostname i.e. contents of /etc/hostname
populateFromFileContents(locationTags, "pod_name", hostnameFile,
GlobalLocationTags::applyTrim);
// container_id: parsed from /proc/self/cgroup . Note: only works for Linux-based containers
populateFromFileContents(locationTags, "container_id", cgroupFile,
(value) -> getContainerIdFromFileContents(value));
}
@VisibleForTesting
static void populateFromFileContents(ImmutableMap.Builder<String, String> locationTags,
String key, String filePath, Function<String, String> parser) {
String value = parser.apply(readFileContents(filePath));
if (value != null) {
locationTags.put(key, value);
}
}
/**
* Parse from a line such as this.
* 1:name=systemd:/kubepods/burstable/podf5143dd2/de67c4419b20924eaa141813
*
* @param value file contents
* @return container-id parsed ("podf5143dd2/de67c4419b20924eaa141813" from the above snippet)
*/
@VisibleForTesting static String getContainerIdFromFileContents(String value) {
if (value != null) {
try (Scanner scanner = new Scanner(value)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] tokens = line.split(":");
if (tokens.length == 3 && tokens[2].startsWith("/kubepods/burstable/")) {
tokens = tokens[2].split("/");
if (tokens.length == 5) {
return tokens[4];
}
}
}
}
}
return null;
}
private static String readFileContents(String file) {
Path fileName = Paths.get(file);
if (Files.isReadable(fileName)) {
try {
byte[] bytes = Files.readAllBytes(fileName);
return new String(bytes, Charsets.US_ASCII);
} catch (IOException e) {
logger.log(Level.FINE, "Reading file:" + file, e);
}
} else {
logger.log(Level.FINE, "File:" + file + " is not readable (or missing?)");
}
return null;
}
static void populate(ImmutableMap.Builder<String, String> locationTags) {
populateFromMetadataServer(locationTags);
populateFromKubernetesValues(locationTags,
"/var/run/secrets/kubernetes.io/serviceaccount/namespace",
"/etc/hostname", "/proc/self/cgroup");
}
private static class DefaultHttpTransportFactory implements HttpTransportFactory {
private static final HttpTransport netHttpTransport = new NetHttpTransport();
@Override
public HttpTransport create() {
return netHttpTransport;
}
}
}

View File

@ -1,107 +0,0 @@
/*
* Copyright 2022 The gRPC Authors
*
* 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 io.grpc.gcp.observability;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpStatusCodes;
import com.google.api.client.http.HttpTransport;
import com.google.auth.http.HttpTransportFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
/** Class to read Google Metadata Server values. */
final class MetadataConfig {
private static final Logger logger = Logger.getLogger(MetadataConfig.class.getName());
private static final int TIMEOUT_MS = 5000;
private static final String METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/";
private HttpRequestFactory requestFactory;
private HttpTransportFactory transportFactory;
@VisibleForTesting public MetadataConfig(HttpTransportFactory transportFactory) {
this.transportFactory = transportFactory;
}
void init() {
HttpTransport httpTransport = transportFactory.create();
requestFactory = httpTransport.createRequestFactory();
}
/** gets all the values from the MDS we need to set in our logging tags. */
ImmutableMap<String, String> getAllValues() {
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
//addValueFor(builder, "instance/hostname", "GCE_INSTANCE_HOSTNAME");
addValueFor(builder, "instance/id", "gke_node_id");
//addValueFor(builder, "instance/zone", "GCE_INSTANCE_ZONE");
addValueFor(builder, "project/project-id", "project_id");
addValueFor(builder, "project/numeric-project-id", "project_numeric_id");
addValueFor(builder, "instance/attributes/cluster-name", "cluster_name");
addValueFor(builder, "instance/attributes/cluster-uid", "cluster_uid");
addValueFor(builder, "instance/attributes/cluster-location", "location");
try {
requestFactory.getTransport().shutdown();
} catch (IOException e) {
logger.log(Level.FINE, "Calling HttpTransport.shutdown()", e);
}
return builder.buildOrThrow();
}
void addValueFor(ImmutableMap.Builder<String, String> builder, String attribute, String key) {
try {
String value = getAttribute(attribute);
if (value != null) {
builder.put(key, value);
}
} catch (IOException e) {
logger.log(Level.FINE, "Calling getAttribute('" + attribute + "')", e);
}
}
String getAttribute(String attributeName) throws IOException {
GenericUrl url = new GenericUrl(METADATA_URL + attributeName);
HttpRequest request = requestFactory.buildGetRequest(url);
request = request.setReadTimeout(TIMEOUT_MS);
request = request.setConnectTimeout(TIMEOUT_MS);
request = request.setHeaders(new HttpHeaders().set("Metadata-Flavor", "Google"));
HttpResponse response = null;
try {
response = request.execute();
if (response.getStatusCode() == HttpStatusCodes.STATUS_CODE_OK) {
InputStream stream = response.getContent();
if (stream != null) {
byte[] bytes = new byte[stream.available()];
stream.read(bytes);
return new String(bytes, response.getContentCharset());
}
}
} finally {
if (response != null) {
response.disconnect();
}
}
return null;
}
}

View File

@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.api.gax.batching.BatchingSettings; import com.google.api.gax.batching.BatchingSettings;
import com.google.api.gax.batching.FlowController; import com.google.api.gax.batching.FlowController;
import com.google.cloud.MonitoredResource;
import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.LogEntry;
import com.google.cloud.logging.Logging; import com.google.cloud.logging.Logging;
import com.google.cloud.logging.LoggingOptions; import com.google.cloud.logging.LoggingOptions;
@ -30,7 +29,6 @@ import com.google.cloud.logging.v2.stub.LoggingServiceV2StubSettings;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.util.JsonFormat; import com.google.protobuf.util.JsonFormat;
import io.grpc.Internal; import io.grpc.Internal;
import io.grpc.gcp.observability.ObservabilityConfig; import io.grpc.gcp.observability.ObservabilityConfig;
@ -42,8 +40,6 @@ import java.time.Instant;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.threeten.bp.Duration; import org.threeten.bp.Duration;
@ -58,13 +54,8 @@ public class GcpLogSink implements Sink {
private static final String DEFAULT_LOG_NAME = private static final String DEFAULT_LOG_NAME =
"microservices.googleapis.com%2Fobservability%2Fgrpc"; "microservices.googleapis.com%2Fobservability%2Fgrpc";
private static final Severity DEFAULT_LOG_LEVEL = Severity.DEBUG; private static final Severity DEFAULT_LOG_LEVEL = Severity.DEBUG;
private static final String K8S_MONITORED_RESOURCE_TYPE = "k8s_container";
private static final Set<String> kubernetesResourceLabelSet
= ImmutableSet.of("project_id", "location", "cluster_name", "namespace_name",
"pod_name", "container_name");
private final String projectId; private final String projectId;
private final Map<String, String> customTags; private final Map<String, String> customTags;
private final MonitoredResource kubernetesResource;
/** Lazily initialize cloud logging client to avoid circular initialization. Because cloud /** Lazily initialize cloud logging client to avoid circular initialization. Because cloud
* logging APIs also uses gRPC. */ * logging APIs also uses gRPC. */
private volatile Logging gcpLoggingClient; private volatile Logging gcpLoggingClient;
@ -75,10 +66,10 @@ public class GcpLogSink implements Sink {
@VisibleForTesting @VisibleForTesting
GcpLogSink(Logging loggingClient, String projectId, Map<String, String> locationTags, GcpLogSink(Logging loggingClient, String projectId,
ObservabilityConfig config, Collection<String> servicesToExclude, ObservabilityConfig config, Collection<String> servicesToExclude,
TraceLoggingHelper traceLoggingHelper) { TraceLoggingHelper traceLoggingHelper) {
this(projectId, locationTags, config, servicesToExclude, traceLoggingHelper); this(projectId, config, servicesToExclude, traceLoggingHelper);
this.gcpLoggingClient = loggingClient; this.gcpLoggingClient = loggingClient;
} }
@ -88,12 +79,11 @@ public class GcpLogSink implements Sink {
* @param projectId GCP project id to write logs * @param projectId GCP project id to write logs
* @param servicesToExclude service names for which log entries should not be generated * @param servicesToExclude service names for which log entries should not be generated
*/ */
public GcpLogSink(String projectId, Map<String, String> locationTags, public GcpLogSink(String projectId,
ObservabilityConfig config, Collection<String> servicesToExclude, ObservabilityConfig config, Collection<String> servicesToExclude,
TraceLoggingHelper traceLoggingHelper) { TraceLoggingHelper traceLoggingHelper) {
this.projectId = projectId; this.projectId = projectId;
this.customTags = getCustomTags(config.getCustomTags(), locationTags, projectId); this.customTags = getCustomTags(config.getCustomTags());
this.kubernetesResource = getResource(locationTags);
this.servicesToExclude = checkNotNull(servicesToExclude, "servicesToExclude"); this.servicesToExclude = checkNotNull(servicesToExclude, "servicesToExclude");
this.isTraceEnabled = config.isEnableCloudTracing(); this.isTraceEnabled = config.isEnableCloudTracing();
this.traceLoggingHelper = traceLoggingHelper; this.traceLoggingHelper = traceLoggingHelper;
@ -126,7 +116,6 @@ public class GcpLogSink implements Sink {
LogEntry.newBuilder(JsonPayload.of(logProtoMap)) LogEntry.newBuilder(JsonPayload.of(logProtoMap))
.setSeverity(DEFAULT_LOG_LEVEL) .setSeverity(DEFAULT_LOG_LEVEL)
.setLogName(DEFAULT_LOG_NAME) .setLogName(DEFAULT_LOG_NAME)
.setResource(kubernetesResource)
.setTimestamp(Instant.now()); .setTimestamp(Instant.now());
if (!customTags.isEmpty()) { if (!customTags.isEmpty()) {
@ -178,34 +167,14 @@ public class GcpLogSink implements Sink {
} }
@VisibleForTesting @VisibleForTesting
static Map<String, String> getCustomTags(Map<String, String> customTags, static Map<String, String> getCustomTags(Map<String, String> customTags) {
Map<String, String> locationTags, String projectId) {
ImmutableMap.Builder<String, String> tagsBuilder = ImmutableMap.builder(); ImmutableMap.Builder<String, String> tagsBuilder = ImmutableMap.builder();
String sourceProjectId = locationTags.get("project_id");
if (!Strings.isNullOrEmpty(projectId)
&& !Strings.isNullOrEmpty(sourceProjectId)
&& !Objects.equals(sourceProjectId, projectId)) {
tagsBuilder.put("source_project_id", sourceProjectId);
}
if (customTags != null) { if (customTags != null) {
tagsBuilder.putAll(customTags); tagsBuilder.putAll(customTags);
} }
return tagsBuilder.buildOrThrow(); return tagsBuilder.buildOrThrow();
} }
@VisibleForTesting
static MonitoredResource getResource(Map<String, String> resourceTags) {
MonitoredResource.Builder builder = MonitoredResource.newBuilder(K8S_MONITORED_RESOURCE_TYPE);
if ((resourceTags != null) && !resourceTags.isEmpty()) {
for (Map.Entry<String, String> entry : resourceTags.entrySet()) {
String resourceKey = entry.getKey();
if (kubernetesResourceLabelSet.contains(resourceKey)) {
builder.addLabel(resourceKey, entry.getValue());
}
}
}
return builder.build();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Map<String, Object> protoToMapConverter(GrpcLogRecord logProto) private Map<String, Object> protoToMapConverter(GrpcLogRecord logProto)

View File

@ -1,110 +0,0 @@
/*
* Copyright 2022 The gRPC Authors
*
* 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 io.grpc.gcp.observability;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class GlobalLocationTagsTest {
private static String FILE_CONTENTS =
"12:perf_event:/kubepods/burstable/podc43b6442-0725-4fb8-bb1c-d17f5122155c/"
+ "fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7\n"
+ "11:freezer:/kubepods/burstable/podc43b6442-0725-4fb8-bb1c-d17f5122155c/"
+ "fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7\n"
+ "2:rdma:/\n"
+ "1:name=systemd:/kubepods/burstable/podc43b6442-0725-4fb8-bb1c-d17f5122155c/"
+ "fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7\n"
+ "0::/system.slice/containerd.service\n";
private static String FILE_CONTENTS_LAST_LINE =
"0::/system.slice/containerd.service\n"
+ "6442-0725-4fb8-bb1c-d17f5122155cslslsl/fe61ca6482b58f4a9831d08d6ea15db25f\n"
+ "\n"
+ "12:perf_event:/kubepods/burstable/podc43b6442-0725-4fb8-bb1c-d17f5122155c/e19a54df\n";
@Rule public TemporaryFolder namespaceFolder = new TemporaryFolder();
@Rule public TemporaryFolder hostnameFolder = new TemporaryFolder();
@Rule public TemporaryFolder cgroupFolder = new TemporaryFolder();
@Test
public void testContainerIdParsing_lastLine() {
String containerId = GlobalLocationTags.getContainerIdFromFileContents(FILE_CONTENTS_LAST_LINE);
assertThat(containerId).isEqualTo("e19a54df");
}
@Test
public void testContainerIdParsing_fewerFields_notFound() {
String containerId = GlobalLocationTags.getContainerIdFromFileContents(
"12:/kubepods/burstable/podc43b6442-0725-4fb8-bb1c-d17f5122155c/"
+ "fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7\n");
assertThat(containerId).isNull();
}
@Test
public void testContainerIdParsing_fewerPaths_notFound() {
String containerId = GlobalLocationTags.getContainerIdFromFileContents(
"12:xdf:/kubepods/podc43b6442-0725-4fb8-bb1c-d17f5122155c/"
+ "fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7\n");
assertThat(containerId).isNull();
}
@Test
public void testPopulateKubernetesValues() throws IOException {
File namespaceFile = namespaceFolder.newFile();
File hostnameFile = hostnameFolder.newFile();
File cgroupFile = cgroupFolder.newFile();
Files.write("test-namespace1".getBytes(StandardCharsets.UTF_8), namespaceFile);
Files.write("test-hostname2\n".getBytes(StandardCharsets.UTF_8), hostnameFile);
Files.write(FILE_CONTENTS.getBytes(StandardCharsets.UTF_8), cgroupFile);
ImmutableMap.Builder<String, String> locationTags = ImmutableMap.builder();
GlobalLocationTags.populateFromKubernetesValues(locationTags, namespaceFile.getAbsolutePath(),
hostnameFile.getAbsolutePath(), cgroupFile.getAbsolutePath());
assertThat(locationTags.buildOrThrow()).containsExactly("container_id",
"fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7", "namespace_name",
"test-namespace1", "pod_name", "test-hostname2");
}
@Test
public void testNonKubernetesInstanceValues() throws IOException {
String namespaceFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
File hostnameFile = hostnameFolder.newFile();
File cgroupFile = cgroupFolder.newFile();
Files.write("test-hostname2\n".getBytes(StandardCharsets.UTF_8), hostnameFile);
Files.write(FILE_CONTENTS.getBytes(StandardCharsets.UTF_8), cgroupFile);
ImmutableMap.Builder<String, String> locationTags = ImmutableMap.builder();
GlobalLocationTags.populateFromKubernetesValues(locationTags,
namespaceFilePath, hostnameFile.getAbsolutePath(), cgroupFile.getAbsolutePath());
assertThat(locationTags.buildOrThrow()).containsExactly("container_id",
"fe61ca6482b58f4a9831d08d6ea15db25f9fd19b4be19a54df8c6c0eab8742b7",
"pod_name", "test-hostname2");
}
}

View File

@ -63,12 +63,6 @@ public class LoggingTest {
public static final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); public static final GrpcCleanupRule cleanupRule = new GrpcCleanupRule();
private static final String PROJECT_ID = "PROJECT"; private static final String PROJECT_ID = "PROJECT";
private static final ImmutableMap<String, String> LOCATION_TAGS = ImmutableMap.of(
"project_id", "PROJECT",
"location", "us-central1-c",
"cluster_name", "grpc-observability-cluster",
"namespace_name", "default" ,
"pod_name", "app1-6c7c58f897-n92c5");
private static final ImmutableMap<String, String> CUSTOM_TAGS = ImmutableMap.of( private static final ImmutableMap<String, String> CUSTOM_TAGS = ImmutableMap.of(
"KEY1", "Value1", "KEY1", "Value1",
"KEY2", "VALUE2"); "KEY2", "VALUE2");
@ -119,7 +113,7 @@ public class LoggingTest {
when(config.getCustomTags()).thenReturn(CUSTOM_TAGS); when(config.getCustomTags()).thenReturn(CUSTOM_TAGS);
Sink sink = Sink sink =
new GcpLogSink( new GcpLogSink(
PROJECT_ID, LOCATION_TAGS, config, Collections.emptySet(), PROJECT_ID, config, Collections.emptySet(),
mock(TraceLoggingHelper.class)); mock(TraceLoggingHelper.class));
LogHelper spyLogHelper = spy(new LogHelper(sink)); LogHelper spyLogHelper = spy(new LogHelper(sink));
ConfigFilterHelper mockFilterHelper = mock(ConfigFilterHelper.class); ConfigFilterHelper mockFilterHelper = mock(ConfigFilterHelper.class);

View File

@ -1,56 +0,0 @@
/*
* Copyright 2022 The gRPC Authors
*
* 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 io.grpc.gcp.observability;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import com.google.api.client.testing.http.MockHttpTransport;
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
import com.google.auth.http.HttpTransportFactory;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(JUnit4.class)
public class MetadataConfigTest {
@Mock HttpTransportFactory httpTransportFactory;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetAttribute() throws IOException {
MockHttpTransport.Builder builder = new MockHttpTransport.Builder();
MockLowLevelHttpResponse response = new MockLowLevelHttpResponse();
response.setContent("foo");
builder.setLowLevelHttpResponse(response);
MockHttpTransport httpTransport = builder.build();
when(httpTransportFactory.create()).thenReturn(httpTransport);
MetadataConfig metadataConfig = new MetadataConfig(httpTransportFactory);
metadataConfig.init();
String val = metadataConfig.getAttribute("instance/attributes/cluster-name");
assertThat(val).isEqualTo("foo");
}
}

View File

@ -24,7 +24,6 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.google.cloud.MonitoredResource;
import com.google.cloud.logging.LogEntry; import com.google.cloud.logging.LogEntry;
import com.google.cloud.logging.Logging; import com.google.cloud.logging.Logging;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
@ -64,12 +63,6 @@ public class GcpLogSinkTest {
@Rule @Rule
public final MockitoRule mockito = MockitoJUnit.rule(); public final MockitoRule mockito = MockitoJUnit.rule();
private static final ImmutableMap<String, String> LOCATION_TAGS =
ImmutableMap.of("project_id", "PROJECT",
"location", "us-central1-c",
"cluster_name", "grpc-observability-cluster",
"namespace_name", "default" ,
"pod_name", "app1-6c7c58f897-n92c5");
private static final ImmutableMap<String, String> CUSTOM_TAGS = private static final ImmutableMap<String, String> CUSTOM_TAGS =
ImmutableMap.of("KEY1", "Value1", ImmutableMap.of("KEY1", "Value1",
"KEY2", "VALUE2"); "KEY2", "VALUE2");
@ -119,7 +112,7 @@ public class GcpLogSinkTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void verifyWrite() throws Exception { public void verifyWrite() throws Exception {
when(mockConfig.getCustomTags()).thenReturn(CUSTOM_TAGS); when(mockConfig.getCustomTags()).thenReturn(CUSTOM_TAGS);
GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME));
sink.write(LOG_PROTO, null); sink.write(LOG_PROTO, null);
@ -138,9 +131,8 @@ public class GcpLogSinkTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void verifyWriteWithTags() { public void verifyWriteWithTags() {
when(mockConfig.getCustomTags()).thenReturn(CUSTOM_TAGS); when(mockConfig.getCustomTags()).thenReturn(CUSTOM_TAGS);
GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME));
MonitoredResource expectedMonitoredResource = GcpLogSink.getResource(LOCATION_TAGS);
sink.write(LOG_PROTO, null); sink.write(LOG_PROTO, null);
ArgumentCaptor<Collection<LogEntry>> logEntrySetCaptor = ArgumentCaptor.forClass( ArgumentCaptor<Collection<LogEntry>> logEntrySetCaptor = ArgumentCaptor.forClass(
@ -149,7 +141,6 @@ public class GcpLogSinkTest {
System.out.println(logEntrySetCaptor.getValue()); System.out.println(logEntrySetCaptor.getValue());
for (Iterator<LogEntry> it = logEntrySetCaptor.getValue().iterator(); it.hasNext(); ) { for (Iterator<LogEntry> it = logEntrySetCaptor.getValue().iterator(); it.hasNext(); ) {
LogEntry entry = it.next(); LogEntry entry = it.next();
assertThat(entry.getResource()).isEqualTo(expectedMonitoredResource);
assertThat(entry.getLabels()).isEqualTo(CUSTOM_TAGS); assertThat(entry.getLabels()).isEqualTo(CUSTOM_TAGS);
assertThat(entry.getPayload().getData()).isEqualTo(EXPECTED_STRUCT_LOG_PROTO); assertThat(entry.getPayload().getData()).isEqualTo(EXPECTED_STRUCT_LOG_PROTO);
assertThat(entry.getLogName()).isEqualTo(EXPECTED_LOG_NAME); assertThat(entry.getLogName()).isEqualTo(EXPECTED_LOG_NAME);
@ -163,7 +154,7 @@ public class GcpLogSinkTest {
Map<String, String> emptyCustomTags = null; Map<String, String> emptyCustomTags = null;
when(mockConfig.getCustomTags()).thenReturn(emptyCustomTags); when(mockConfig.getCustomTags()).thenReturn(emptyCustomTags);
Map<String, String> expectedEmptyLabels = new HashMap<>(); Map<String, String> expectedEmptyLabels = new HashMap<>();
GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME));
sink.write(LOG_PROTO, null); sink.write(LOG_PROTO, null);
@ -183,9 +174,9 @@ public class GcpLogSinkTest {
Map<String, String> emptyCustomTags = null; Map<String, String> emptyCustomTags = null;
when(mockConfig.getCustomTags()).thenReturn(emptyCustomTags); when(mockConfig.getCustomTags()).thenReturn(emptyCustomTags);
String projectId = "PROJECT"; String projectId = "PROJECT";
Map<String, String> expectedLabels = GcpLogSink.getCustomTags(emptyCustomTags, LOCATION_TAGS, Map<String, String> expectedLabels = GcpLogSink.getCustomTags(emptyCustomTags
projectId); );
GcpLogSink sink = new GcpLogSink(mockLogging, projectId, LOCATION_TAGS, GcpLogSink sink = new GcpLogSink(mockLogging, projectId,
mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME));
sink.write(LOG_PROTO, null); sink.write(LOG_PROTO, null);
@ -201,7 +192,7 @@ public class GcpLogSinkTest {
@Test @Test
public void verifyClose() throws Exception { public void verifyClose() throws Exception {
GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, GcpLogSink sink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.emptySet(), new TraceLoggingHelper(DEST_PROJECT_NAME));
sink.write(LOG_PROTO, null); sink.write(LOG_PROTO, null);
verify(mockLogging, times(1)).write(anyIterable()); verify(mockLogging, times(1)).write(anyIterable());
@ -212,7 +203,7 @@ public class GcpLogSinkTest {
@Test @Test
public void verifyExclude() throws Exception { public void verifyExclude() throws Exception {
Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.singleton("service"), new TraceLoggingHelper(DEST_PROJECT_NAME)); mockConfig, Collections.singleton("service"), new TraceLoggingHelper(DEST_PROJECT_NAME));
mockSink.write(LOG_PROTO, null); mockSink.write(LOG_PROTO, null);
verifyNoInteractions(mockLogging); verifyNoInteractions(mockLogging);
@ -229,7 +220,7 @@ public class GcpLogSinkTest {
TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME); TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME);
when(mockConfig.isEnableCloudTracing()).thenReturn(false); when(mockConfig.isEnableCloudTracing()).thenReturn(false);
Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), traceLoggingHelper); mockConfig, Collections.emptySet(), traceLoggingHelper);
mockSink.write(LOG_PROTO, validSpanContext); mockSink.write(LOG_PROTO, validSpanContext);
@ -260,7 +251,7 @@ public class GcpLogSinkTest {
TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME); TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME);
when(mockConfig.isEnableCloudTracing()).thenReturn(true); when(mockConfig.isEnableCloudTracing()).thenReturn(true);
Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), traceLoggingHelper); mockConfig, Collections.emptySet(), traceLoggingHelper);
mockSink.write(LOG_PROTO, validSpanContext); mockSink.write(LOG_PROTO, validSpanContext);
@ -284,7 +275,7 @@ public class GcpLogSinkTest {
public void verifyTraceDataLogs_withNullSpanContext() throws Exception { public void verifyTraceDataLogs_withNullSpanContext() throws Exception {
TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME); TraceLoggingHelper traceLoggingHelper = new TraceLoggingHelper(DEST_PROJECT_NAME);
when(mockConfig.isEnableCloudTracing()).thenReturn(true); when(mockConfig.isEnableCloudTracing()).thenReturn(true);
Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME, LOCATION_TAGS, Sink mockSink = new GcpLogSink(mockLogging, DEST_PROJECT_NAME,
mockConfig, Collections.emptySet(), traceLoggingHelper); mockConfig, Collections.emptySet(), traceLoggingHelper);
String expectedTrace = String expectedTrace =