Skip to content

Commit c5ba02a

Browse files
authored
Add resource package (census-instrumentation#1555)
* Add resource package * Fix review comments * Add package-info * Fix minor nits
1 parent a549400 commit c5ba02a

4 files changed

Lines changed: 420 additions & 0 deletions

File tree

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Copyright 2018, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opencensus.resource;
18+
19+
import com.google.auto.value.AutoValue;
20+
import io.opencensus.common.ExperimentalApi;
21+
import io.opencensus.internal.DefaultVisibilityForTesting;
22+
import io.opencensus.internal.StringUtils;
23+
import io.opencensus.internal.Utils;
24+
import java.util.Collections;
25+
import java.util.HashMap;
26+
import java.util.LinkedHashMap;
27+
import java.util.Map;
28+
import javax.annotation.Nullable;
29+
import javax.annotation.concurrent.Immutable;
30+
31+
/**
32+
* {@link Resource} represents a resource, which capture identifying information about the entities
33+
* for which signals (stats or traces) are reported. It further provides a framework for detection
34+
* of resource information from the environment and progressive population as signals propagate from
35+
* the core instrumentation library to a backend's exporter.
36+
*
37+
* @since 0.18
38+
*/
39+
@Immutable
40+
@AutoValue
41+
@ExperimentalApi
42+
public abstract class Resource {
43+
@DefaultVisibilityForTesting static final int MAX_LENGTH = 255;
44+
private static final String OC_RESOURCE_TYPE_ENV = "OC_RESOURCE_TYPE";
45+
private static final String OC_RESOURCE_LABELS_ENV = "OC_RESOURCE_LABELS";
46+
private static final String LABEL_LIST_SPLITTER = ",";
47+
private static final String LABEL_KEY_VALUE_SPLITTER = "=";
48+
private static final String ERROR_MESSAGE_INVALID_CHARS =
49+
" should be a ASCII string with a length greater than 0 and not exceed "
50+
+ MAX_LENGTH
51+
+ " characters.";
52+
private static final String ERROR_MESSAGE_INVALID_VALUE =
53+
" should be a ASCII string with a length not exceed " + MAX_LENGTH + " characters.";
54+
55+
@Nullable
56+
private static final String ENV_TYPE = parseResourceType(System.getenv(OC_RESOURCE_TYPE_ENV));
57+
58+
private static final Map<String, String> ENV_LABEL_MAP =
59+
parseResourceLabels(System.getenv(OC_RESOURCE_LABELS_ENV));
60+
61+
Resource() {}
62+
63+
/**
64+
* Returns the type identifier for the resource.
65+
*
66+
* @return the type identifier for the resource.
67+
* @since 0.18
68+
*/
69+
@Nullable
70+
public abstract String getType();
71+
72+
/**
73+
* Returns a map of labels that describe the resource.
74+
*
75+
* @return a map of labels.
76+
* @since 0.18
77+
*/
78+
public abstract Map<String, String> getLabels();
79+
80+
/**
81+
* Returns a {@link Resource}. This resource information is loaded from the OC_RESOURCE_TYPE and
82+
* OC_RESOURCE_LABELS environment variables.
83+
*
84+
* @return a {@code Resource}.
85+
* @since 0.18
86+
*/
87+
public static Resource create() {
88+
return createInternal(ENV_TYPE, ENV_LABEL_MAP);
89+
}
90+
91+
/**
92+
* Returns a {@link Resource}.
93+
*
94+
* @param type the type identifier for the resource.
95+
* @param labels a map of labels that describe the resource.
96+
* @return a {@code Resource}.
97+
* @throws NullPointerException if {@code labels} is null.
98+
* @throws IllegalArgumentException if type or label key or label value is not a valid printable
99+
* ASCII string or exceed {@link #MAX_LENGTH} characters.
100+
* @since 0.18
101+
*/
102+
public static Resource create(@Nullable String type, Map<String, String> labels) {
103+
return createInternal(
104+
type,
105+
Collections.unmodifiableMap(
106+
new LinkedHashMap<String, String>(Utils.checkNotNull(labels, "labels"))));
107+
}
108+
109+
private static Resource createInternal(@Nullable String type, Map<String, String> labels) {
110+
return new AutoValue_Resource(type, labels);
111+
}
112+
113+
/**
114+
* Creates a resource type from the OC_RESOURCE_TYPE environment variable.
115+
*
116+
* <p>OC_RESOURCE_TYPE: A string that describes the type of the resource prefixed by a domain
117+
* namespace, e.g. “kubernetes.io/container”.
118+
*/
119+
@Nullable
120+
static String parseResourceType(@Nullable String rawEnvType) {
121+
if (rawEnvType != null && !rawEnvType.isEmpty()) {
122+
Utils.checkArgument(isValidAndNotEmpty(rawEnvType), "Type" + ERROR_MESSAGE_INVALID_CHARS);
123+
return rawEnvType.trim();
124+
}
125+
return rawEnvType;
126+
}
127+
128+
/*
129+
* Creates a label map from the OC_RESOURCE_LABELS environment variable.
130+
*
131+
* <p>OC_RESOURCE_LABELS: A comma-separated list of labels describing the source in more detail,
132+
* e.g. “key1=val1,key2=val2”. Domain names and paths are accepted as label keys. Values may be
133+
* quoted or unquoted in general. If a value contains whitespaces, =, or " characters, it must
134+
* always be quoted.
135+
*/
136+
static Map<String, String> parseResourceLabels(@Nullable String rawEnvLabels) {
137+
if (rawEnvLabels == null) {
138+
return Collections.<String, String>emptyMap();
139+
} else {
140+
Map<String, String> labels = new HashMap<String, String>();
141+
String[] rawLabels = rawEnvLabels.split(LABEL_LIST_SPLITTER, -1);
142+
for (String rawLabel : rawLabels) {
143+
String[] keyValuePair = rawLabel.split(LABEL_KEY_VALUE_SPLITTER, -1);
144+
if (keyValuePair.length != 2) {
145+
continue;
146+
}
147+
String key = keyValuePair[0].trim();
148+
String value = keyValuePair[1].trim().replaceAll("^\"|\"$", "");
149+
Utils.checkArgument(isValidAndNotEmpty(key), "Label key" + ERROR_MESSAGE_INVALID_CHARS);
150+
Utils.checkArgument(isValid(value), "Label value" + ERROR_MESSAGE_INVALID_VALUE);
151+
labels.put(key, value);
152+
}
153+
return Collections.unmodifiableMap(labels);
154+
}
155+
}
156+
157+
/**
158+
* Determines whether the given {@code String} is a valid printable ASCII string with a length not
159+
* exceed {@link #MAX_LENGTH} characters.
160+
*
161+
* @param name the name to be validated.
162+
* @return whether the name is valid.
163+
*/
164+
static boolean isValid(String name) {
165+
return name.length() <= MAX_LENGTH && StringUtils.isPrintableString(name);
166+
}
167+
168+
/**
169+
* Determines whether the given {@code String} is a valid printable ASCII string with a length
170+
* greater than 0 and not exceed {@link #MAX_LENGTH} characters.
171+
*
172+
* @param name the name to be validated.
173+
* @return whether the name is valid.
174+
*/
175+
static boolean isValidAndNotEmpty(String name) {
176+
return !name.isEmpty() && isValid(name);
177+
}
178+
179+
// TODO(mayurkale): Add detector interface as per specs:
180+
// https://github.com/census-instrumentation/opencensus-specs/blob/master/resource/Resource.md.
181+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2018, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* API for resource information population.
19+
*
20+
* <p>The resource library primarily defines a type "Resource" that captures information about the
21+
* entity for which stats or traces are recorded. For example, metrics exposed by a Kubernetes
22+
* container can be linked to a resource that specifies the cluster, namespace, pod, and container
23+
* name.
24+
*
25+
* <p>Two environment variables are used to populate resource information:
26+
*
27+
* <ul>
28+
* <li>OC_RESOURCE_TYPE: A string that describes the type of the resource prefixed by a domain
29+
* namespace. Leading and trailing whitespaces are trimmed. e.g. “kubernetes.io/container”.
30+
* <li>OC_RESOURCE_LABELS: A comma-separated list of labels describing the source in more detail,
31+
* e.g. “key1=val1,key2=val2”. The allowed character set is appropriately constrained.
32+
* </ul>
33+
*
34+
* <p>Type, label keys, and label values MUST contain only printable ASCII (codes between 32 and
35+
* 126, inclusive) and less than 256 characters. Type and label keys MUST have a length greater than
36+
* zero. They SHOULD start with a domain name and separate hierarchies with / characters, e.g.
37+
* k8s.io/namespace/name.
38+
*
39+
* <p>WARNING: Currently all the public classes under this package are marked as {@link
40+
* io.opencensus.common.ExperimentalApi}. DO NOT USE except for experimental purposes.
41+
*
42+
* <p>Please see
43+
* https://github.com/census-instrumentation/opencensus-specs/blob/master/resource/Resource.md for
44+
* more details.
45+
*/
46+
@io.opencensus.common.ExperimentalApi
47+
package io.opencensus.resource;

0 commit comments

Comments
 (0)