Skip to content
This repository has been archived by the owner on Dec 23, 2023. It is now read-only.

Commit

Permalink
Exporter/OCAgent: Add OcAgentNodeUtils. (#1471)
Browse files Browse the repository at this point in the history
* Exporter/OCAgent: Add OcAgentNodeUtils.

Add utilities for detecting and creating Node.
Equivalent to
https://github.com/census-ecosystem/opencensus-go-exporter-ocagent/blob/master/nodeinfo.go.

* Fix nullness checker.

* Use a local VERSION string in OC-Agent Exporter.
  • Loading branch information
songy23 authored Sep 26, 2018
1 parent 8ca4546 commit 9580d5f
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 4 deletions.
1 change: 1 addition & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ token](https://help.github.com/articles/creating-a-personal-access-token-for-the
examples/build.gradle
examples/pom.xml
api/src/main/java/io/opencensus/common/OpenCensusLibraryInformation.java
exporters/trace/ocagent/src/main/java/io/opencensus/exporter/trace/ocagent/OcAgentNodeUtils.java
)
$ git checkout -b v$MAJOR.$MINOR.x master
$ git push upstream v$MAJOR.$MINOR.x
Expand Down
1 change: 1 addition & 0 deletions buildscripts/import-control.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ General guidelines on imports:
</subpackage>
<subpackage name="ocagent">
<allow pkg="com.google.protobuf"/>
<allow pkg="io.opencensus.contrib.monitoredresource.util"/>
<allow pkg="io.opencensus.contrib.opencensus.proto.util"/>
<allow pkg="io.opencensus.exporter.trace.ocagent"/>
<allow pkg="io.opencensus.proto"/>
Expand Down
1 change: 0 additions & 1 deletion exporters/trace/ocagent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ dependencies {
testCompile project(':opencensus-api')

signature "org.codehaus.mojo.signature:java17:1.0@signature"
signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright 2018, OpenCensus 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.opencensus.exporter.trace.ocagent;

import com.google.common.annotations.VisibleForTesting;
import io.opencensus.common.OpenCensusLibraryInformation;
import io.opencensus.common.Timestamp;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.AwsEc2InstanceMonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.GcpGceInstanceMonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.GcpGkeContainerMonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResourceUtils;
import io.opencensus.proto.agent.common.v1.LibraryInfo;
import io.opencensus.proto.agent.common.v1.LibraryInfo.Language;
import io.opencensus.proto.agent.common.v1.Node;
import io.opencensus.proto.agent.common.v1.ProcessIdentifier;
import io.opencensus.proto.agent.common.v1.ServiceInfo;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

/** Utilities for detecting and creating {@link Node}. */
final class OcAgentNodeUtils {

// The current version of the OpenCensus OC-Agent Exporter.
@VisibleForTesting
static final String OC_AGENT_EXPORTER_VERSION = "0.17.0-SNAPSHOT"; // CURRENT_OPENCENSUS_VERSION

@VisibleForTesting static final String RESOURCE_TYPE_ATTRIBUTE_KEY = "OPENCENSUS_SOURCE_TYPE";
@VisibleForTesting static final String RESOURCE_LABEL_ATTRIBUTE_KEY = "OPENCENSUS_SOURCE_LABELS";

@Nullable
private static final MonitoredResource RESOURCE = MonitoredResourceUtils.getDefaultResource();

// Creates a Node with information from the OpenCensus library and environment variables.
static Node getNodeInfo(String serviceName) {
String jvmName = ManagementFactory.getRuntimeMXBean().getName();
Timestamp censusTimestamp = Timestamp.fromMillis(System.currentTimeMillis());
return Node.newBuilder()
.setIdentifier(getProcessIdentifier(jvmName, censusTimestamp))
.setLibraryInfo(getLibraryInfo(OpenCensusLibraryInformation.VERSION))
.setServiceInfo(getServiceInfo(serviceName))
.putAllAttributes(getAttributeMap(RESOURCE))
.build();
}

// Creates process identifier with the given JVM name and start time.
@VisibleForTesting
static ProcessIdentifier getProcessIdentifier(String jvmName, Timestamp censusTimestamp) {
String hostname;
int pid;
// jvmName should be something like '<pid>@<hostname>', at least in Oracle and OpenJdk JVMs
int delimiterIndex = jvmName.indexOf('@');
if (delimiterIndex < 1) {
// Not the expected format, generate a random number.
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
hostname = "localhost";
}
// Generate a random number as the PID.
pid = new SecureRandom().nextInt();
} else {
hostname = jvmName.substring(delimiterIndex + 1, jvmName.length());
try {
pid = Integer.parseInt(jvmName.substring(0, delimiterIndex));
} catch (NumberFormatException e) {
// Generate a random number as the PID if format is unexpected.
pid = new SecureRandom().nextInt();
}
}

return ProcessIdentifier.newBuilder()
.setHostName(hostname)
.setPid(pid)
.setStartTimestamp(TraceProtoUtils.toTimestampProto(censusTimestamp))
.build();
}

// Creates library info with the given OpenCensus Java version.
@VisibleForTesting
static LibraryInfo getLibraryInfo(String currentOcJavaVersion) {
return LibraryInfo.newBuilder()
.setLanguage(Language.JAVA)
.setCoreLibraryVersion(currentOcJavaVersion)
.setExporterVersion(OC_AGENT_EXPORTER_VERSION)
.build();
}

// Creates service info with the given service name.
@VisibleForTesting
static ServiceInfo getServiceInfo(String serviceName) {
return ServiceInfo.newBuilder().setName(serviceName).build();
}

/*
* Creates an attribute map with the given MonitoredResource.
* If the given resource is not null, the attribute map contains exactly two entries:
*
* OPENCENSUS_SOURCE_TYPE:
* A string that describes the type of the resource prefixed by a domain namespace,
* e.g. “kubernetes.io/container”.
* OPENCENSUS_SOURCE_LABELS:
* A comma-separated list of labels describing the source in more detail,
* e.g. “key1=val1,key2=val2”. The allowed character set is appropriately constrained.
*/
// TODO: update the resource attributes once we have an agreement on the resource specs:
// https://github.com/census-instrumentation/opencensus-specs/pull/162.
@VisibleForTesting
static Map<String, String> getAttributeMap(@Nullable MonitoredResource resource) {
if (resource == null) {
return Collections.emptyMap();
} else {
Map<String, String> resourceAttributes = new HashMap<String, String>();
resourceAttributes.put(RESOURCE_TYPE_ATTRIBUTE_KEY, resource.getResourceType().name());
resourceAttributes.put(RESOURCE_LABEL_ATTRIBUTE_KEY, getConcatenatedResourceLabels(resource));
return resourceAttributes;
}
}

// Encodes the attributes of MonitoredResource into a comma-separated list of labels.
// For example "aws_account=account1,instance_id=instance1,region=us-east-2".
private static String getConcatenatedResourceLabels(MonitoredResource resource) {
StringBuilder resourceLabels = new StringBuilder();
if (resource instanceof AwsEc2InstanceMonitoredResource) {
AwsEc2InstanceMonitoredResource awsEc2Resource = (AwsEc2InstanceMonitoredResource) resource;
putIntoBuilderIfHasValue(resourceLabels, "aws_account", awsEc2Resource.getAccount());
putIntoBuilderIfHasValue(resourceLabels, "instance_id", awsEc2Resource.getInstanceId());
putIntoBuilderIfHasValue(resourceLabels, "region", awsEc2Resource.getRegion());
} else if (resource instanceof GcpGceInstanceMonitoredResource) {
GcpGceInstanceMonitoredResource gceResource = (GcpGceInstanceMonitoredResource) resource;
putIntoBuilderIfHasValue(resourceLabels, "gcp_account", gceResource.getAccount());
putIntoBuilderIfHasValue(resourceLabels, "instance_id", gceResource.getInstanceId());
putIntoBuilderIfHasValue(resourceLabels, "zone", gceResource.getZone());
} else if (resource instanceof GcpGkeContainerMonitoredResource) {
GcpGkeContainerMonitoredResource gkeResource = (GcpGkeContainerMonitoredResource) resource;
putIntoBuilderIfHasValue(resourceLabels, "gcp_account", gkeResource.getAccount());
putIntoBuilderIfHasValue(resourceLabels, "instance_id", gkeResource.getInstanceId());
putIntoBuilderIfHasValue(resourceLabels, "location", gkeResource.getZone());
putIntoBuilderIfHasValue(resourceLabels, "namespace_name", gkeResource.getNamespaceId());
putIntoBuilderIfHasValue(resourceLabels, "cluster_name", gkeResource.getClusterName());
putIntoBuilderIfHasValue(resourceLabels, "container_name", gkeResource.getContainerName());
putIntoBuilderIfHasValue(resourceLabels, "pod_name", gkeResource.getPodId());
}
return resourceLabels.toString();
}

// If the given resourceValue is not empty, encodes resourceKey and resourceValue as
// "resourceKey:resourceValue" and puts it into the given StringBuilder. Otherwise skip the value.
private static void putIntoBuilderIfHasValue(
StringBuilder builder, String resourceKey, String resourceValue) {
if (resourceValue.isEmpty()) {
return;
}
if (!(builder.length() == 0)) {
// Appends the comma separator to the front, if the StringBuilder already has entries.
builder.append(',');
}
builder.append(resourceKey);
builder.append('=');
builder.append(resourceValue);
}

private OcAgentNodeUtils() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ final class OcAgentTraceExporterHandler extends Handler {
private static final String DEFAULT_SERVICE_NAME = "OpenCensus";

// private final String endPoint;
// private final String serviceName;
// private final Node node;
// private final boolean useInsecure;

OcAgentTraceExporterHandler() {
Expand All @@ -38,7 +38,10 @@ final class OcAgentTraceExporterHandler extends Handler {
OcAgentTraceExporterHandler(
@Nullable String endPoint, @Nullable String serviceName, @Nullable Boolean useInsecure) {
// this.endPoint = endPoint == null ? DEFAULT_END_POINT : endPoint;
// this.serviceName = serviceName == null ? DEFAULT_SERVICE_NAME : serviceName;
// if (serviceName == null) {
// serviceName = DEFAULT_SERVICE_NAME;
// }
// this.node = OcAgentNodeUtils.getNodeInfo(serviceName);
// this.useInsecure = useInsecure == null ? false : useInsecure;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ static TruncatableString toTruncatableStringProto(String string) {
return TruncatableString.newBuilder().setValue(string).setTruncatedByteCount(0).build();
}

private static com.google.protobuf.Timestamp toTimestampProto(Timestamp timestamp) {
static com.google.protobuf.Timestamp toTimestampProto(Timestamp timestamp) {
return com.google.protobuf.Timestamp.newBuilder()
.setSeconds(timestamp.getSeconds())
.setNanos(timestamp.getNanos())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2018, OpenCensus 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.opencensus.exporter.trace.ocagent;

import static com.google.common.truth.Truth.assertThat;
import static io.opencensus.exporter.trace.ocagent.OcAgentNodeUtils.OC_AGENT_EXPORTER_VERSION;
import static io.opencensus.exporter.trace.ocagent.OcAgentNodeUtils.RESOURCE_LABEL_ATTRIBUTE_KEY;
import static io.opencensus.exporter.trace.ocagent.OcAgentNodeUtils.RESOURCE_TYPE_ATTRIBUTE_KEY;

import io.opencensus.common.Timestamp;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.AwsEc2InstanceMonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.GcpGceInstanceMonitoredResource;
import io.opencensus.contrib.monitoredresource.util.MonitoredResource.GcpGkeContainerMonitoredResource;
import io.opencensus.proto.agent.common.v1.LibraryInfo;
import io.opencensus.proto.agent.common.v1.LibraryInfo.Language;
import io.opencensus.proto.agent.common.v1.ProcessIdentifier;
import io.opencensus.proto.agent.common.v1.ServiceInfo;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link OcAgentNodeUtils}. */
@RunWith(JUnit4.class)
public class OcAgentNodeUtilsTest {

private static final AwsEc2InstanceMonitoredResource AWS_RESOURCE =
AwsEc2InstanceMonitoredResource.create("account1", "instance1", "us-east-2");
private static final GcpGceInstanceMonitoredResource GCE_RESOURCE =
GcpGceInstanceMonitoredResource.create("account2", "instance2", "us-west2");
private static final GcpGkeContainerMonitoredResource GKE_RESOURCE =
GcpGkeContainerMonitoredResource.create(
"account3", "cluster", "container", "", "instance3", "", "us-west4");

@Test
public void testConstants() {
assertThat(OC_AGENT_EXPORTER_VERSION).isEqualTo("0.17.0-SNAPSHOT");
assertThat(RESOURCE_TYPE_ATTRIBUTE_KEY).isEqualTo("OPENCENSUS_SOURCE_TYPE");
assertThat(RESOURCE_LABEL_ATTRIBUTE_KEY).isEqualTo("OPENCENSUS_SOURCE_LABELS");
}

@Test
public void getProcessIdentifier() {
String jvmName = "[email protected]";
Timestamp timestamp = Timestamp.create(10, 20);
ProcessIdentifier processIdentifier = OcAgentNodeUtils.getProcessIdentifier(jvmName, timestamp);
assertThat(processIdentifier.getHostName()).isEqualTo("my.org");
assertThat(processIdentifier.getPid()).isEqualTo(54321);
assertThat(processIdentifier.getStartTimestamp())
.isEqualTo(com.google.protobuf.Timestamp.newBuilder().setSeconds(10).setNanos(20).build());
}

@Test
public void getLibraryInfo() {
String currentOcJavaVersion = "0.16.0";
LibraryInfo libraryInfo = OcAgentNodeUtils.getLibraryInfo(currentOcJavaVersion);
assertThat(libraryInfo.getLanguage()).isEqualTo(Language.JAVA);
assertThat(libraryInfo.getCoreLibraryVersion()).isEqualTo(currentOcJavaVersion);
assertThat(libraryInfo.getExporterVersion()).isEqualTo(OC_AGENT_EXPORTER_VERSION);
}

@Test
public void getServiceInfo() {
String serviceName = "my-service";
ServiceInfo serviceInfo = OcAgentNodeUtils.getServiceInfo(serviceName);
assertThat(serviceInfo.getName()).isEqualTo(serviceName);
}

@Test
public void getAttributeMap_Null() {
Map<String, String> attributeMap = OcAgentNodeUtils.getAttributeMap(null);
assertThat(attributeMap).isEmpty();
}

@Test
public void getAttributeMap_AwsEc2Resource() {
Map<String, String> attributeMap = OcAgentNodeUtils.getAttributeMap(AWS_RESOURCE);
assertThat(attributeMap)
.containsExactly(
RESOURCE_TYPE_ATTRIBUTE_KEY,
"AWS_EC2_INSTANCE",
RESOURCE_LABEL_ATTRIBUTE_KEY,
"aws_account=account1,instance_id=instance1,region=us-east-2");
}

@Test
public void getAttributeMap_GceResource() {
Map<String, String> attributeMap = OcAgentNodeUtils.getAttributeMap(GCE_RESOURCE);
assertThat(attributeMap)
.containsExactly(
RESOURCE_TYPE_ATTRIBUTE_KEY,
"GCP_GCE_INSTANCE",
RESOURCE_LABEL_ATTRIBUTE_KEY,
"gcp_account=account2,instance_id=instance2,zone=us-west2");
}

@Test
public void getAttributeMap_GkeResource() {
Map<String, String> attributeMap = OcAgentNodeUtils.getAttributeMap(GKE_RESOURCE);
assertThat(attributeMap)
.containsExactly(
RESOURCE_TYPE_ATTRIBUTE_KEY,
"GCP_GKE_CONTAINER",
RESOURCE_LABEL_ATTRIBUTE_KEY,
"gcp_account=account3,instance_id=instance3,location=us-west4,"
+ "cluster_name=cluster,container_name=container");
}
}

0 comments on commit 9580d5f

Please sign in to comment.