Last active
March 8, 2024 02:23
-
-
Save Cantido/6d5496d3bf41e05d604bb93d5bd80764 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule AwsResourceDetector do | |
@moduledoc """ | |
Fetches data about the AWS environment the app is running in, | |
and provides that to OpenTelemetry. | |
Add this module to the `:opentelemetry` application configuration to run it. | |
Remember to keep the default detectors in place. | |
config :opentelemetry, | |
resource_detectors: [ | |
:otel_resource_env_var, | |
:otel_resource_app_env, | |
AwsResourceDetector | |
] | |
# See Also | |
- <https://github.com/open-telemetry/opentelemetry-erlang/tree/main/apps/opentelemetry#resource-detectors> | |
- <https://hexdocs.pm/opentelemetry/otel_resource_detector.html> | |
- <https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-metadata-endpoint-v4.html> | |
- <https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/> | |
""" | |
require Logger | |
@behaviour :otel_resource_detector | |
@impl true | |
def get_resource(_) do | |
# The metadata URI is added to the environment by ECS when the container is started. | |
with {:ok, uri} <- System.fetch_env("ECS_CONTAINER_METADATA_URI_V4"), | |
{:ok, container_metadata} <- get_json(uri), | |
{:ok, task_metadata} <- get_json(uri <> "/task") do | |
[image_name, image_tag] = | |
Map.fetch!(container_metadata, "Image") | |
|> String.split(":", parts: 2) | |
["arn", "aws", "ecs", region, account_id, _rest] = | |
Map.fetch!(task_metadata, "TaskARN") | |
|> String.split(":", parts: 6) | |
:otel_resource.create(%{ | |
"aws.ecs.container.arn" => Map.fetch!(container_metadata, "ContainerARN"), | |
"aws.ecs.cluster.arn" => Map.fetch!(task_metadata, "Cluster"), | |
"aws.ecs.launchtype" => String.downcase(Map.fetch!(task_metadata, "LaunchType")), | |
"aws.ecs.task.arn" => Map.fetch!(task_metadata, "TaskARN"), | |
"aws.ecs.task.family" => Map.fetch!(task_metadata, "Family"), | |
"aws.ecs.task.revision" => Map.fetch!(task_metadata, "Revision"), | |
"container.name" => Map.fetch!(container_metadata, "DockerName"), | |
"container.id" => Map.fetch!(container_metadata, "DockerId"), | |
"container.runtime" => "docker", | |
"container.image.name" => image_name, | |
"container.image.tag" => image_tag, | |
"cloud.provider" => "aws", | |
"cloud.account.id" => account_id, | |
"cloud.region" => region, | |
"cloud.availability_zone" => Map.fetch!(task_metadata, "AvailabilityZone"), | |
"cloud.platform" => "aws_ecs" | |
}) | |
else | |
:error -> | |
Logger.warning( | |
"Failed to find AWS ECS metadata URI. We will not pull ECS resource information for OpenTelemetry." | |
) | |
:otel_resource.create(%{}) | |
error -> | |
Logger.error("Failed to fetch AWS ECS metadata: #{inspect(error)}") | |
:otel_resource.create(%{}) | |
end | |
end | |
defp get_json(uri) do | |
case OpenTelemetryHTTPoison.get(uri) do | |
{:ok, %HTTPoison.Response{status_code: status} = response} when status in 200..299 -> | |
{:ok, Jason.decode!(response.body)} | |
{:ok, response} -> | |
{:error, response} | |
error -> | |
error | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment