Skip to content

Instantly share code, notes, and snippets.

@Cantido
Last active March 8, 2024 02:23
Show Gist options
  • Save Cantido/6d5496d3bf41e05d604bb93d5bd80764 to your computer and use it in GitHub Desktop.
Save Cantido/6d5496d3bf41e05d604bb93d5bd80764 to your computer and use it in GitHub Desktop.
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