1515
1616package com .amazonaws .xray .plugins ;
1717
18+ import com .amazonaws .xray .entities .AWSLogReference ;
1819import com .amazonaws .xray .utils .DockerUtils ;
1920import java .io .IOException ;
2021import java .net .InetAddress ;
2122import java .net .UnknownHostException ;
2223import java .util .HashMap ;
24+ import java .util .HashSet ;
2325import java .util .Map ;
26+ import java .util .Set ;
2427import org .apache .commons .logging .Log ;
2528import org .apache .commons .logging .LogFactory ;
2629import org .checkerframework .checker .nullness .qual .Nullable ;
@@ -38,29 +41,43 @@ public class ECSPlugin implements Plugin {
3841 private static final Log logger = LogFactory .getLog (ECSPlugin .class );
3942
4043 private static final String SERVICE_NAME = "ecs" ;
41- private static final String ECS_METADATA_KEY = "ECS_CONTAINER_METADATA_URI" ;
42- private static final String HTTP_PREFIX = "http:// " ;
44+ private static final String ECS_METADATA_V3_KEY = "ECS_CONTAINER_METADATA_URI" ;
45+ private static final String ECS_METADATA_V4_KEY = "ECS_CONTAINER_METADATA_URI_V4 " ;
4346 private static final String CONTAINER_ID_KEY = "container_id" ;
47+ private static final String CONTAINER_NAME_KEY = "container" ;
48+ private static final String CONTAINER_ARN_KEY = "container_arn" ;
4449
50+ private final ECSMetadataFetcher fetcher ;
4551 private final HashMap <String , @ Nullable Object > runtimeContext ;
4652 private final DockerUtils dockerUtils ;
53+ private final Set <AWSLogReference > logReferences ;
54+ private final Map <ECSMetadataFetcher .ECSContainerMetadata , String > containerMetadata ;
4755
56+ @ SuppressWarnings ("nullness:method.invocation.invalid" )
4857 public ECSPlugin () {
4958 runtimeContext = new HashMap <>();
5059 dockerUtils = new DockerUtils ();
60+ logReferences = new HashSet <>();
61+ fetcher = new ECSMetadataFetcher (getTmdeFromEnv ());
62+ containerMetadata = this .fetcher .fetchContainer ();
63+ }
64+
65+ // Exposed for testing
66+ ECSPlugin (ECSMetadataFetcher fetcher ) {
67+ runtimeContext = new HashMap <>();
68+ dockerUtils = new DockerUtils ();
69+ logReferences = new HashSet <>();
70+ this .fetcher = fetcher ;
71+ containerMetadata = this .fetcher .fetchContainer ();
5172 }
5273
5374 /**
5475 * Returns true if the environment variable added by ECS is present and contains a valid URI
5576 */
5677 @ Override
5778 public boolean isEnabled () {
58- String ecsMetadataUri = System .getenv (ECS_METADATA_KEY );
59- if (ecsMetadataUri == null ) {
60- return false ;
61- }
62-
63- return ecsMetadataUri .startsWith (HTTP_PREFIX );
79+ String ecsMetadataUri = getTmdeFromEnv ();
80+ return ecsMetadataUri != null && ecsMetadataUri .startsWith ("http://" );
6481 }
6582
6683 @ Override
@@ -70,7 +87,7 @@ public String getServiceName() {
7087
7188 public void populateRuntimeContext () {
7289 try {
73- runtimeContext .put ("container" , InetAddress .getLocalHost ().getHostName ());
90+ runtimeContext .put (CONTAINER_NAME_KEY , InetAddress .getLocalHost ().getHostName ());
7491 } catch (UnknownHostException uhe ) {
7592 logger .error ("Could not get docker container ID from hostname." , uhe );
7693 }
@@ -80,6 +97,10 @@ public void populateRuntimeContext() {
8097 } catch (IOException e ) {
8198 logger .error ("Failed to read full container ID from container instance." , e );
8299 }
100+
101+ if (containerMetadata .containsKey (ECSMetadataFetcher .ECSContainerMetadata .CONTAINER_ARN )) {
102+ runtimeContext .put (CONTAINER_ARN_KEY , containerMetadata .get (ECSMetadataFetcher .ECSContainerMetadata .CONTAINER_ARN ));
103+ }
83104 }
84105
85106 @ Override
@@ -88,6 +109,34 @@ public void populateRuntimeContext() {
88109 return runtimeContext ;
89110 }
90111
112+ @ Override
113+ public Set <AWSLogReference > getLogReferences () {
114+ if (logReferences .isEmpty ()) {
115+ populateLogReferences ();
116+ }
117+
118+ return logReferences ;
119+ }
120+
121+ // See: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids
122+ private void populateLogReferences () {
123+ String logGroup = containerMetadata .get (ECSMetadataFetcher .ECSContainerMetadata .LOG_GROUP_NAME );
124+ if (logGroup == null ) {
125+ return ;
126+ }
127+ AWSLogReference logReference = new AWSLogReference ();
128+ logReference .setLogGroup (logGroup );
129+
130+ String logRegion = containerMetadata .get (ECSMetadataFetcher .ECSContainerMetadata .LOG_GROUP_REGION );
131+ String containerArn = containerMetadata .get (ECSMetadataFetcher .ECSContainerMetadata .CONTAINER_ARN );
132+ String logAccount = containerArn != null ? containerArn .split (":" )[4 ] : null ;
133+
134+ if (logRegion != null && logAccount != null ) {
135+ logReference .setArn ("arn:aws:logs:" + logRegion + ":" + logAccount + ":log-group:" + logGroup );
136+ }
137+ logReferences .add (logReference );
138+ }
139+
91140 @ Override
92141 public String getOrigin () {
93142 return ORIGIN ;
@@ -109,4 +158,17 @@ public boolean equals(@Nullable Object o) {
109158 public int hashCode () {
110159 return this .getOrigin ().hashCode ();
111160 }
161+
162+ /**
163+ * @return V4 Metadata endpoint if present, otherwise V3 endpoint if present, otherwise null
164+ */
165+ @ Nullable
166+ private String getTmdeFromEnv () {
167+ String ecsMetadataUri = System .getenv (ECS_METADATA_V4_KEY );
168+ if (ecsMetadataUri == null ) {
169+ ecsMetadataUri = System .getenv (ECS_METADATA_V3_KEY );
170+ }
171+
172+ return ecsMetadataUri ;
173+ }
112174}
0 commit comments