opentelemetry-dotnet-contrib icon indicating copy to clipboard operation
opentelemetry-dotnet-contrib copied to clipboard

Add ECS Task Metadata

Open RichiCoder1 opened this issue 2 years ago • 2 comments

Issue with OpenTelemetry.Contrib.Extensions.AWSXRay

List of all OpenTelemetry NuGet packages and version that you are using (e.g. OpenTelemetry 1.0.2):

  • OpenTelemetry.Contrib.Extensions.AWSXRay Latest

Runtime version (e.g. net462, net48, netcoreapp3.1, net6.0 etc. You can find this information from the *.csproj file):

  • net6.0

Is this a feature request or a bug?

  • [x] Feature Request
  • [ ] Bug

What is the expected behavior?

All relevant Container and Cloud runtime information included in Resource information

What is the actual behavior?

Only container.id, cloud.platform, and cloud.provider set.

Additional Context

I believe this is because getting the rest of the information requires pinging the Metadata endpoint for a given task, and this is normally an async operation. However, as of .NET 5, there's a sync request method that could be used to retrieve this information. I propose adding in the rest of the missing cloud and container information conditionally.

RichiCoder1 avatar Jul 08 '22 17:07 RichiCoder1

My very PoC implementation of the above:

    private class ECSExtendedDetector : OpenTelemetry.Resources.IResourceDetector
    {
        private readonly AWSECSResourceDetector _awsDetecter = new();
        public Resource Detect()
        {
            var ecsBase = _awsDetecter.Detect();
            if (ecsBase is null) return Resource.Empty;

            var ecsMetaUrl = Environment.GetEnvironmentVariable("ECS_CONTAINER_METADATA_URI_V4");
            if (ecsMetaUrl is null) {
                return Resource.Empty;
            }

            var ecsResourceBase = new Resource(ecsBase);

            var containerId = ecsBase.First(pair => pair.Key == "container.id").Value as string;

            using var client = new HttpClient();
            var containerMetaRequest = new HttpRequestMessage(HttpMethod.Get, ecsMetaUrl);
            var containerMetaResult = client.Send(containerMetaRequest);
            if (!containerMetaResult.IsSuccessStatusCode) {
                return ecsResourceBase;
            }

            var taskMetaRequest = new HttpRequestMessage(HttpMethod.Get, $"{ecsMetaUrl}/task");
            var taskMetaResult = client.Send(taskMetaRequest);
            if (!taskMetaResult.IsSuccessStatusCode) {
                return ecsResourceBase;
            }

            var containerMeta = JsonSerializer.Deserialize<JsonDocument>(containerMetaResult.Content.ReadAsStream())!.RootElement!;
            var taskMeta = JsonSerializer.Deserialize<JsonDocument>(taskMetaResult.Content.ReadAsStream())!.RootElement!;

            var taskArn = Amazon.Arn.Parse(taskMeta!.GetProperty("TaskARN").GetString());
            var image = containerMeta!.GetProperty("Image").ToString()!;
            var imageParts = image.Split(":", 2);

            return ecsResourceBase.Merge(new Resource(new Dictionary<string, object> {
                {"cloud.account.id", taskArn.AccountId},
                {"cloud.region", taskArn.Region},
                {"cloud.availability_zone", taskMeta.GetProperty("AvailabilityZone").GetString()!},
                {"container.name", containerMeta.GetProperty("Name").GetString()!},
                {"container.image.name", imageParts[0]},
                {"container.image.tag", imageParts[1]},
                {"aws.ecs.container.arn", containerMeta.GetProperty("ContainerARN").GetString()!},
                {"aws.ecs.cluster.arn", $"arn:aws:ecs:${taskArn.Region}:${taskArn.AccountId}:cluster/{taskMeta.GetProperty("Cluster").GetString()!}"},
                {"aws.ecs.launchtype", taskMeta.GetProperty("LaunchType").GetString()!.ToLowerInvariant()},
                {"aws.ecs.task.arn", taskArn.ToString()},
                {"aws.ecs.task.family", taskMeta.GetProperty("Family").GetString()!},
                {"aws.ecs.task.revision", int.Parse(taskMeta.GetProperty("Revision").GetString()!)},
            }));
        }
    }

RichiCoder1 avatar Jul 09 '22 05:07 RichiCoder1