Skip to content

Commit

Permalink
otel: collect telemetry for otel configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
mabdinur committed Nov 11, 2024
1 parent f9e96e9 commit 438834b
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 37 deletions.
75 changes: 38 additions & 37 deletions ddtrace/settings/_otel_remapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from ..constants import ENV_KEY
from ..constants import VERSION_KEY
from ..internal.logger import get_logger
from ..internal.telemetry import telemetry_writer


if sys.version_info >= (3, 8):
Expand All @@ -21,19 +22,13 @@
}


def _remap_otel_log_level(otel_value: str) -> str:
def _remap_otel_log_level(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel log level to ddtrace log level"""
if otel_value == "debug":
return "True"
else:
log.warning(
"ddtrace does not support otel log level '%s'. ddtrace only supports enabling debug logs.",
otel_value,
)
return "False"


def _remap_otel_propagators(otel_value: str) -> str:
def _remap_otel_propagators(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel propagators to ddtrace propagators"""
accepted_styles = []
for style in otel_value.split(","):
Expand All @@ -46,7 +41,7 @@ def _remap_otel_propagators(otel_value: str) -> str:
return ",".join(accepted_styles)


def _remap_traces_sampler(otel_value: str) -> str:
def _remap_traces_sampler(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel trace sampler to ddtrace trace sampler"""
if otel_value in ["always_on", "always_off", "traceidratio"]:
log.warning(
Expand All @@ -61,42 +56,27 @@ def _remap_traces_sampler(otel_value: str) -> str:
return "0.0"
elif otel_value == "parentbased_traceidratio":
return os.environ.get("OTEL_TRACES_SAMPLER_ARG", "1")
else:
log.warning("Unknown sampling configuration: %s.", otel_value)
return otel_value


def _remap_traces_exporter(otel_value: str) -> str:
def _remap_traces_exporter(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel trace exporter to ddtrace trace enabled"""
if otel_value == "none":
return "False"
log.warning(
"A trace exporter value '%s' is set, but not supported. Traces will be exported to Datadog.", otel_value
)
return ""


def _remap_metrics_exporter(otel_value: str) -> str:
def _remap_metrics_exporter(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel metrics exporter to ddtrace metrics exporter"""
if otel_value == "none":
return "False"
log.warning(
"Metrics exporter value is set to unrecognized value: %s.",
otel_value,
)
return ""


def _validate_logs_exporter(otel_value: str) -> typing.Literal[""]:
"""Logs warning when OTEL Logs exporter is configured. DDTRACE does not support this configuration."""
if otel_value != "none":
log.warning(
"Unsupported OTEL logs exporter value detected: %s. Only the 'none' value is supported.", otel_value
)
return ""
if otel_value == "none":
return ""


def _remap_otel_tags(otel_value: str) -> str:
def _remap_otel_tags(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel tags to ddtrace tags"""
dd_tags: typing.List[str] = []

Expand All @@ -113,7 +93,7 @@ def _remap_otel_tags(otel_value: str) -> str:
else:
dd_tags.append(f"{key}:{value}")
except Exception:
log.warning("DDTRACE failed to read OTEL_RESOURCE_ATTRIBUTES. This value is misformatted: %s", otel_value)
return

if len(dd_tags) > 10:
dd_tags, remaining_tags = dd_tags[:10], dd_tags[10:]
Expand All @@ -126,23 +106,20 @@ def _remap_otel_tags(otel_value: str) -> str:
return ",".join(dd_tags)


def _remap_otel_sdk_config(otel_value: str) -> str:
def _remap_otel_sdk_config(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel sdk config to ddtrace sdk config"""
if otel_value == "false":
return "True"
elif otel_value == "true":
return "False"
else:
log.warning("OTEL_SDK_DISABLED='%s' is not supported", otel_value)
return otel_value


def _remap_default(otel_value: str) -> str:
def _remap_default(otel_value: str) -> typing.Optional[str]:
"""Remaps the otel default value to ddtrace default value"""
return otel_value


ENV_VAR_MAPPINGS = {
ENV_VAR_MAPPINGS: typing.Dict[str, typing.Tuple[str, typing.Callable[[str], typing.Optional[str]]]] = {
"OTEL_SERVICE_NAME": ("DD_SERVICE", _remap_default),
"OTEL_LOG_LEVEL": ("DD_TRACE_DEBUG", _remap_otel_log_level),
"OTEL_PROPAGATORS": ("DD_TRACE_PROPAGATION_STYLE", _remap_otel_propagators),
Expand All @@ -164,6 +141,11 @@ def otel_remapping():

for otel_env, otel_value in user_envs.items():
if otel_env not in ENV_VAR_MAPPINGS:
if otel_env.startswith("OTEL_"):
log.warning("OpenTelemetry configuration %s is not supported by Datadog.", otel_env)
telemetry_writer.add_count_metric(
"tracer", "otel.env.unsupported", 1, (("config_opentelemetry", otel_env.lower()),)
)
continue

dd_env, otel_config_validator = ENV_VAR_MAPPINGS[otel_env]
Expand All @@ -174,14 +156,33 @@ def otel_remapping():
otel_env,
otel_value,
)
telemetry_writer.add_count_metric(
"tracer",
"otel.env.hiding",
1,
(("config_opentelemetry", otel_env.lower()), ("config_datadog", dd_env.lower())),
)
continue

if otel_env not in ("OTEL_RESOURCE_ATTRIBUTES", "OTEL_SERVICE_NAME"):
# Resource attributes and service name are case-insensitive
otel_value = otel_value.lower()

telemetry_writer.add_configuration(otel_env, otel_value, "env_var")
mapped_value = otel_config_validator(otel_value)
if mapped_value:
if mapped_value is None:
log.warning(
"Setting %s to %s is not supported by ddtrace, this configuration will be ignored.",
otel_env,
otel_value,
)
telemetry_writer.add_count_metric(
"tracer",
"otel.env.invalid",
1,
(("config_opentelemetry", otel_env.lower()), ("config_datadog", dd_env.lower())),
)
elif mapped_value:
os.environ[dd_env] = mapped_value
log.debug(
"OpenTelemetry configuration %s has been remapped to ddtrace configuration %s=%s",
Expand Down
61 changes: 61 additions & 0 deletions tests/telemetry/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,3 +813,64 @@ def test_telemetry_writer_is_using_agent_by_default_if_api_key_is_not_available(
assert telemetry_writer._client._endpoint == "telemetry/proxy/api/v2/apmtelemetry"
assert telemetry_writer._client._telemetry_url in ("http://localhost:9126", "http://testagent:9126")
assert "dd-api-key" not in telemetry_writer._client._headers


def test_otel_config_telemetry(test_agent_session, run_python_code_in_subprocess, tmpdir):
"""
asserts that telemetry data is submitted for OpenTelemetry configurations
"""

env = os.environ.copy()
env["DD_SERVICE"] = "dd_service"
env["OTEL_SERVICE_NAME"] = "otel_service"
env["OTEL_LOG_LEVEL"] = "DEBUG"
env["OTEL_PROPAGATORS"] = "tracecontext"
env["OTEL_TRACES_SAMPLER"] = "always_on"
env["OTEL_TRACES_EXPORTER"] = "none"
env["OTEL_LOGS_EXPORTER"] = "otlp"
env["OTEL_RESOURCE_ATTRIBUTES"] = "team=apm,component=web"
env["OTEL_SDK_DISABLED"] = "true"
env["OTEL_UNSUPPORTED_CONFIG"] = "value"
env["_DD_INSTRUMENTATION_TELEMETRY_TESTS_FORCE_APP_STARTED"] = "true"

_, stderr, status, _ = run_python_code_in_subprocess("import ddtrace", env=env)
assert status == 0, stderr

configurations = {c["name"]: c for c in test_agent_session.get_configurations()}

assert configurations["DD_SERVICE"] == {"name": "DD_SERVICE", "origin": "env_var", "value": "dd_service"}
assert configurations["OTEL_LOG_LEVEL"] == {"name": "OTEL_LOG_LEVEL", "origin": "env_var", "value": "debug"}
assert configurations["OTEL_PROPAGATORS"] == {
"name": "OTEL_PROPAGATORS",
"origin": "env_var",
"value": "tracecontext",
}
assert configurations["OTEL_TRACES_SAMPLER"] == {
"name": "OTEL_TRACES_SAMPLER",
"origin": "env_var",
"value": "always_on",
}
assert configurations["OTEL_TRACES_EXPORTER"] == {
"name": "OTEL_TRACES_EXPORTER",
"origin": "env_var",
"value": "none",
}
assert configurations["OTEL_LOGS_EXPORTER"] == {"name": "OTEL_LOGS_EXPORTER", "origin": "env_var", "value": "otlp"}
assert configurations["OTEL_RESOURCE_ATTRIBUTES"] == {
"name": "OTEL_RESOURCE_ATTRIBUTES",
"origin": "env_var",
"value": "team=apm,component=web",
}
assert configurations["OTEL_SDK_DISABLED"] == {"name": "OTEL_SDK_DISABLED", "origin": "env_var", "value": "true"}

env_hiding_metrics = test_agent_session.get_metrics("otel.env.hiding")
tags = [m["tags"] for m in env_hiding_metrics]
assert tags == [["config_opentelemetry:otel_service_name", "config_datadog:dd_service"]]

env_unsupported_metrics = test_agent_session.get_metrics("otel.env.unsupported")
tags = [m["tags"] for m in env_unsupported_metrics]
assert tags == [["config_opentelemetry:otel_unsupported_config"]]

env_invalid_metrics = test_agent_session.get_metrics("otel.env.invalid")
tags = [m["tags"] for m in env_invalid_metrics]
assert tags == [["config_opentelemetry:otel_logs_exporter", "config_datadog:"]]

0 comments on commit 438834b

Please sign in to comment.