Skip to content

Commit

Permalink
Make sure Resources follow semantic conventions (#1480)
Browse files Browse the repository at this point in the history
  • Loading branch information
hectorhdzg authored Jan 25, 2021
1 parent 6489bf5 commit 0e04658
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 35 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased](https://github.com/open-telemetry/opentelemetry-python/compare/v0.17b0...HEAD)

=======
### Added
- Added `end_on_exit` argument to `start_as_current_span`
([#1519](https://github.com/open-telemetry/opentelemetry-python/pull/1519)])
- Add `Span.set_attributes` method to set multiple values with one call
([#1520](https://github.com/open-telemetry/opentelemetry-python/pull/1520))
- Make sure Resources follow semantic conventions
([#1480](https://github.com/open-telemetry/opentelemetry-python/pull/1480))

## [0.17b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v0.17b0) - 2021-01-20

Expand Down
68 changes: 66 additions & 2 deletions opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,62 @@
logger = logging.getLogger(__name__)


TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language"
CLOUD_PROVIDER = "cloud.provider"
CLOUD_ACCOUNT_ID = "cloud.account.id"
CLOUD_REGION = "cloud.region"
CLOUD_ZONE = "cloud.zone"
CONTAINER_NAME = "container.name"
CONTAINER_ID = "container.id"
CONTAINER_IMAGE_NAME = "container.image.name"
CONTAINER_IMAGE_TAG = "container.image.tag"
DEPLOYMENT_ENVIRONMENT = "deployment.environment"
FAAS_NAME = "faas.name"
FAAS_ID = "faas.id"
FAAS_VERSION = "faas.version"
FAAS_INSTANCE = "faas.instance"
HOST_NAME = "host.name"
HOST_TYPE = "host.type"
HOST_IMAGE_NAME = "host.image.name"
HOST_IMAGE_ID = "host.image.id"
HOST_IMAGE_VERSION = "host.image.version"
KUBERNETES_CLUSTER_NAME = "k8s.cluster.name"
KUBERNETES_NAMESPACE_NAME = "k8s.namespace.name"
KUBERNETES_POD_UID = "k8s.pod.uid"
KUBERNETES_POD_NAME = "k8s.pod.name"
KUBERNETES_CONTAINER_NAME = "k8s.container.name"
KUBERNETES_REPLICA_SET_UID = "k8s.replicaset.uid"
KUBERNETES_REPLICA_SET_NAME = "k8s.replicaset.name"
KUBERNETES_DEPLOYMENT_UID = "k8s.deployment.uid"
KUBERNETES_DEPLOYMENT_NAME = "k8s.deployment.name"
KUBERNETES_STATEFUL_SET_UID = "k8s.statefulset.uid"
KUBERNETES_STATEFUL_SET_NAME = "k8s.statefulset.name"
KUBERNETES_DAEMON_SET_UID = "k8s.daemonset.uid"
KUBERNETES_DAEMON_SET_NAME = "k8s.daemonset.name"
KUBERNETES_JOB_UID = "k8s.job.uid"
KUBERNETES_JOB_NAME = "k8s.job.name"
KUBERNETES_CRON_JOB_UID = "k8s.cronjob.uid"
KUBERNETES_CRON_JOB_NAME = "k8s.cronjob.name"
OS_TYPE = "os.type"
OS_DESCRIPTION = "os.description"
PROCESS_PID = "process.pid"
PROCESS_EXECUTABLE_NAME = "process.executable.name"
PROCESS_EXECUTABLE_PATH = "process.executable.path"
PROCESS_COMMAND = "process.command"
PROCESS_COMMAND_LINE = "process.command_line"
PROCESS_COMMAND_ARGS = "process.command_args"
PROCESS_OWNER = "process.owner"
PROCESS_RUNTIME_NAME = "process.runtime.name"
PROCESS_RUNTIME_VERSION = "process.runtime.version"
PROCESS_RUNTIME_DESCRIPTION = "process.runtime.description"
SERVICE_NAME = "service.name"
SERVICE_NAMESPACE = "service.namespace"
SERVICE_INSTANCE_ID = "service.instance.id"
SERVICE_VERSION = "service.version"
TELEMETRY_SDK_NAME = "telemetry.sdk.name"
TELEMETRY_SDK_VERSION = "telemetry.sdk.version"
TELEMETRY_AUTO_VERSION = "telemetry.auto.version"
TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language"


OPENTELEMETRY_SDK_VERSION = pkg_resources.get_distribution(
"opentelemetry-sdk"
Expand All @@ -111,7 +164,18 @@ def create(attributes: typing.Optional[Attributes] = None) -> "Resource":
resource = _DEFAULT_RESOURCE
else:
resource = _DEFAULT_RESOURCE.merge(Resource(attributes))
return resource.merge(OTELResourceDetector().detect())
resource = resource.merge(OTELResourceDetector().detect())
if not resource.attributes.get(SERVICE_NAME, None):
default_service_name = "unknown_service"
process_executable_name = resource.attributes.get(
PROCESS_EXECUTABLE_NAME, None
)
if process_executable_name:
default_service_name += ":" + process_executable_name
resource = resource.merge(
Resource({SERVICE_NAME: default_service_name})
)
return resource

@staticmethod
def create_empty() -> "Resource":
Expand Down
48 changes: 35 additions & 13 deletions opentelemetry-sdk/tests/metrics/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,37 @@ def test_stateful(self):
meter = meter_provider.get_meter(__name__)
self.assertIs(meter.processor.stateful, False)

def test_resource(self):
resource = resources.Resource.create({})
def test_resource_empty(self):
resource = resources.Resource.create_empty()
meter_provider = metrics.MeterProvider(resource=resource)
self.assertIs(meter_provider.resource, resource)

def test_resource_empty(self):
def test_resources(self):
meter_provider = metrics.MeterProvider()
# pylint: disable=protected-access
self.assertEqual(meter_provider.resource, resources._DEFAULT_RESOURCE)
self.assertIsInstance(meter_provider.resource, resources.Resource)
self.assertEqual(
meter_provider.resource.attributes.get(resources.SERVICE_NAME),
"unknown_service",
)
self.assertEqual(
meter_provider.resource.attributes.get(
resources.TELEMETRY_SDK_LANGUAGE
),
"python",
)
self.assertEqual(
meter_provider.resource.attributes.get(
resources.TELEMETRY_SDK_NAME
),
"opentelemetry",
)
self.assertEqual(
meter_provider.resource.attributes.get(
resources.TELEMETRY_SDK_VERSION
),
resources.OPENTELEMETRY_SDK_VERSION,
)

def test_start_pipeline(self):
exporter = Mock()
Expand Down Expand Up @@ -74,7 +96,7 @@ def test_collect_metrics(self):
meter = metrics.MeterProvider().get_meter(__name__)
processor_mock = Mock()
meter.processor = processor_mock
counter = meter.create_counter("name", "desc", "unit", float,)
counter = meter.create_counter("name", "desc", "unit", float)
labels = {"key1": "value1"}
meter.register_view(View(counter, SumAggregator))
counter.add(1.0, labels)
Expand Down Expand Up @@ -155,7 +177,7 @@ def test_create_counter(self):
resource = Mock(spec=resources.Resource)
meter_provider = metrics.MeterProvider(resource=resource)
meter = meter_provider.get_meter(__name__)
counter = meter.create_counter("name", "desc", "unit", int,)
counter = meter.create_counter("name", "desc", "unit", int)
self.assertIsInstance(counter, metrics.Counter)
self.assertEqual(counter.value_type, int)
self.assertEqual(counter.name, "name")
Expand All @@ -166,14 +188,14 @@ def test_instrument_same_name_error(self):
resource = Mock(spec=resources.Resource)
meter_provider = metrics.MeterProvider(resource=resource)
meter = meter_provider.get_meter(__name__)
counter = meter.create_counter("name", "desc", "unit", int,)
counter = meter.create_counter("name", "desc", "unit", int)
self.assertIsInstance(counter, metrics.Counter)
self.assertEqual(counter.value_type, int)
self.assertEqual(counter.name, "name")
self.assertIs(meter_provider.resource, resource)
self.assertEqual(counter.meter, meter)
with self.assertRaises(ValueError) as ctx:
_ = meter.create_counter("naME", "desc", "unit", int,)
_ = meter.create_counter("naME", "desc", "unit", int)
self.assertTrue(
"Multiple instruments can't be registered by the same name: (name)"
in str(ctx.exception)
Expand All @@ -182,7 +204,7 @@ def test_instrument_same_name_error(self):
def test_create_updowncounter(self):
meter = metrics.MeterProvider().get_meter(__name__)
updowncounter = meter.create_updowncounter(
"name", "desc", "unit", float,
"name", "desc", "unit", float
)
self.assertIsInstance(updowncounter, metrics.UpDownCounter)
self.assertEqual(updowncounter.value_type, float)
Expand All @@ -191,7 +213,7 @@ def test_create_updowncounter(self):
def test_create_valuerecorder(self):
meter = metrics.MeterProvider().get_meter(__name__)
valuerecorder = meter.create_valuerecorder(
"name", "desc", "unit", float,
"name", "desc", "unit", float
)
self.assertIsInstance(valuerecorder, metrics.ValueRecorder)
self.assertEqual(valuerecorder.value_type, float)
Expand All @@ -204,7 +226,7 @@ def test_register_sumobserver(self):
callback = Mock()

observer = meter.register_sumobserver(
callback, "name", "desc", "unit", int,
callback, "name", "desc", "unit", int
)

self.assertIsInstance(observer, metrics.SumObserver)
Expand All @@ -224,7 +246,7 @@ def test_register_updownsumobserver(self):
callback = Mock()

observer = meter.register_updownsumobserver(
callback, "name", "desc", "unit", int,
callback, "name", "desc", "unit", int
)

self.assertIsInstance(observer, metrics.UpDownSumObserver)
Expand All @@ -244,7 +266,7 @@ def test_register_valueobserver(self):
callback = Mock()

observer = meter.register_valueobserver(
callback, "name", "desc", "unit", int,
callback, "name", "desc", "unit", int
)

self.assertIsInstance(observer, metrics.ValueObserver)
Expand Down
27 changes: 24 additions & 3 deletions opentelemetry-sdk/tests/resources/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def test_create(self):
resources.TELEMETRY_SDK_NAME: "opentelemetry",
resources.TELEMETRY_SDK_LANGUAGE: "python",
resources.TELEMETRY_SDK_VERSION: resources.OPENTELEMETRY_SDK_VERSION,
resources.SERVICE_NAME: "unknown_service",
}

resource = resources.Resource.create(attributes)
Expand All @@ -62,10 +63,20 @@ def test_create(self):
self.assertEqual(resource, resources._EMPTY_RESOURCE)

resource = resources.Resource.create(None)
self.assertEqual(resource, resources._DEFAULT_RESOURCE)
self.assertEqual(
resource,
resources._DEFAULT_RESOURCE.merge(
resources.Resource({resources.SERVICE_NAME: "unknown_service"})
),
)

resource = resources.Resource.create({})
self.assertEqual(resource, resources._DEFAULT_RESOURCE)
self.assertEqual(
resource,
resources._DEFAULT_RESOURCE.merge(
resources.Resource({resources.SERVICE_NAME: "unknown_service"})
),
)

def test_resource_merge(self):
left = resources.Resource({"service": "ui"})
Expand Down Expand Up @@ -103,6 +114,7 @@ def test_immutability(self):
resources.TELEMETRY_SDK_NAME: "opentelemetry",
resources.TELEMETRY_SDK_LANGUAGE: "python",
resources.TELEMETRY_SDK_VERSION: resources.OPENTELEMETRY_SDK_VERSION,
resources.SERVICE_NAME: "unknown_service",
}

attributes_copy = attributes.copy()
Expand All @@ -117,6 +129,15 @@ def test_immutability(self):
attributes["cost"] = 999.91
self.assertEqual(resource.attributes, attributes_copy)

def test_service_name_using_process_name(self):
resource = resources.Resource.create(
{resources.PROCESS_EXECUTABLE_NAME: "test"}
)
self.assertEqual(
resource.attributes.get(resources.SERVICE_NAME),
"unknown_service:test",
)

def test_aggregated_resources_no_detectors(self):
aggregated_resources = resources.get_aggregated_resources([])
self.assertEqual(
Expand Down Expand Up @@ -192,7 +213,7 @@ def test_resource_detector_raise_error(self):
resource_detector.detect.side_effect = Exception()
resource_detector.raise_on_error = True
self.assertRaises(
Exception, resources.get_aggregated_resources, [resource_detector],
Exception, resources.get_aggregated_resources, [resource_detector]
)


Expand Down
42 changes: 25 additions & 17 deletions opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,23 @@ def test_default_span_resource(self):
tracer = tracer_provider.get_tracer(__name__)
span = tracer.start_span("root")
# pylint: disable=protected-access
self.assertEqual(span.resource, resources._DEFAULT_RESOURCE)
self.assertIsInstance(span.resource, resources.Resource)
self.assertEqual(
span.resource.attributes.get(resources.SERVICE_NAME),
"unknown_service",
)
self.assertEqual(
span.resource.attributes.get(resources.TELEMETRY_SDK_LANGUAGE),
"python",
)
self.assertEqual(
span.resource.attributes.get(resources.TELEMETRY_SDK_NAME),
"opentelemetry",
)
self.assertEqual(
span.resource.attributes.get(resources.TELEMETRY_SDK_VERSION),
resources.OPENTELEMETRY_SDK_VERSION,
)

def test_span_context_remote_flag(self):
tracer = new_tracer()
Expand Down Expand Up @@ -835,7 +851,7 @@ def test_start_span(self):
)
span.set_status(new_status)
self.assertIs(
span.status.status_code, trace_api.status.StatusCode.ERROR,
span.status.status_code, trace_api.status.StatusCode.ERROR
)
self.assertIs(span.status.description, "Test description")

Expand Down Expand Up @@ -930,7 +946,7 @@ def error_status_test(context):
with self.assertRaises(AssertionError):
with context as root:
root.set_status(
trace_api.status.Status(StatusCode.OK, "OK",)
trace_api.status.Status(StatusCode.OK, "OK")
)
raise AssertionError("unknown")

Expand Down Expand Up @@ -987,11 +1003,9 @@ def test_record_exception_with_attributes(self):
"RuntimeError: error",
exception_event.attributes["exception.stacktrace"],
)
self.assertIn(
"has_additional_attributes", exception_event.attributes,
)
self.assertIn("has_additional_attributes", exception_event.attributes)
self.assertEqual(
True, exception_event.attributes["has_additional_attributes"],
True, exception_event.attributes["has_additional_attributes"]
)

def test_record_exception_escaped(self):
Expand Down Expand Up @@ -1035,9 +1049,7 @@ def test_record_exception_with_timestamp(self):
"RuntimeError: error",
exception_event.attributes["exception.stacktrace"],
)
self.assertEqual(
1604238587112021089, exception_event.timestamp,
)
self.assertEqual(1604238587112021089, exception_event.timestamp)

def test_record_exception_with_attributes_and_timestamp(self):
span = trace._Span("name", mock.Mock(spec=trace_api.SpanContext))
Expand All @@ -1059,15 +1071,11 @@ def test_record_exception_with_attributes_and_timestamp(self):
"RuntimeError: error",
exception_event.attributes["exception.stacktrace"],
)
self.assertIn(
"has_additional_attributes", exception_event.attributes,
)
self.assertEqual(
True, exception_event.attributes["has_additional_attributes"],
)
self.assertIn("has_additional_attributes", exception_event.attributes)
self.assertEqual(
1604238587112021089, exception_event.timestamp,
True, exception_event.attributes["has_additional_attributes"]
)
self.assertEqual(1604238587112021089, exception_event.timestamp)

def test_record_exception_context_manager(self):
try:
Expand Down

0 comments on commit 0e04658

Please sign in to comment.