All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.xray.plugins.EC2Plugin Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.amazonaws.xray.plugins;

import com.amazonaws.xray.entities.AWSLogReference;
import com.amazonaws.xray.entities.StringValidator;
import com.amazonaws.xray.utils.JsonUtils;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A plugin, for use with the {@code AWSXRayRecorderBuilder} class, which will add EC2 instance information to segments generated
 * by the built {@code AWSXRayRecorder} instance.
 * 
 * @see com.amazonaws.xray.AWSXRayRecorderBuilder#withPlugin(Plugin)
 *
 */
public class EC2Plugin implements Plugin {
    public static final String ORIGIN = "AWS::EC2::Instance";

    private static final Log logger = LogFactory.getLog(EC2Plugin.class);

    private static final String SERVICE_NAME = "ec2";

    private static final String LOG_CONFIGS = "log_configs";
    private static final String LOG_GROUP_NAME = "log_group_name";

    private static final String WINDOWS_PROGRAM_DATA = "ProgramData";
    private static final String WINDOWS_PATH = "\\Amazon\\AmazonCloudWatchAgent\\log-config.json";

    private static final String LINUX_ROOT = "/";
    private static final String LINUX_PATH = "opt/aws/amazon-cloudwatch-agent/etc/log-config.json";

    private final Map runtimeContext;

    private final Set logReferences;

    private final FileSystem fs;

    private final Map metadata;

    public EC2Plugin() {
        this(FileSystems.getDefault(), new EC2MetadataFetcher());
    }

    public EC2Plugin(FileSystem fs, EC2MetadataFetcher metadataFetcher) {
        this.fs = fs;
        metadata = metadataFetcher.fetch();
        runtimeContext = new LinkedHashMap<>();
        logReferences = new HashSet<>();
    }

    @Override
    public boolean isEnabled() {
        return metadata.containsKey(EC2MetadataFetcher.EC2Metadata.INSTANCE_ID);
    }

    @Override
    public String getServiceName() {
        return SERVICE_NAME;
    }

    /**
     * Reads EC2 provided metadata to include it in trace document
     */
    public void populateRuntimeContext() {
        runtimeContext.put("instance_id", metadata.get(EC2MetadataFetcher.EC2Metadata.INSTANCE_ID));
        runtimeContext.put("availability_zone", metadata.get(EC2MetadataFetcher.EC2Metadata.AVAILABILITY_ZONE));
        runtimeContext.put("instance_size", metadata.get(EC2MetadataFetcher.EC2Metadata.INSTANCE_TYPE));
        runtimeContext.put("ami_id", metadata.get(EC2MetadataFetcher.EC2Metadata.AMI_ID));
    }

    @Override
    public Map getRuntimeContext() {
        populateRuntimeContext();
        return runtimeContext;
    }

    /**
     * Reads the log group configuration file generated by the CloudWatch Agent to discover all log groups being used on this
     * instance and populates log reference set with them to be included in trace documents.
     */
    public void populateLogReferences() {
        String filePath = null;
        String programData = System.getenv(WINDOWS_PROGRAM_DATA);

        if (StringValidator.isNullOrBlank(programData)) {
            for (Path root : fs.getRootDirectories()) {
                if (root.toString().equals(LINUX_ROOT)) {
                    filePath = LINUX_ROOT + LINUX_PATH;
                    break;
                }
            }
        } else {
            filePath = programData + WINDOWS_PATH;
        }

        if (filePath == null) {
            logger.warn("X-Ray could not recognize the file system in use. Expected file system to be Linux or Windows based.");
            return;
        }

        try {
            JsonNode logConfigs = JsonUtils.getNodeFromJsonFile(filePath, LOG_CONFIGS);
            List logGroups = JsonUtils.getMatchingListFromJsonArrayNode(logConfigs, LOG_GROUP_NAME);

            for (String logGroup : logGroups) {
                AWSLogReference logReference = new AWSLogReference();
                logReference.setLogGroup(logGroup);
                logReferences.add(logReference);
            }
        } catch (IOException e) {
            logger.warn("CloudWatch Agent log configuration file not found at " + filePath + ". Install the CloudWatch Agent "
                        + "on this instance to record log references in X-Ray.");
        } catch (RuntimeException e) {
            logger.warn("An unexpected exception occurred while reading CloudWatch agent log configuration file at " + filePath
                        + ":\n", e);
        }
    }

    /**
     *
     * @return Set of AWS log references used by CloudWatch agent. The ARN of these log references is not available at this time.
     */
    @Override
    public Set getLogReferences() {
        if (logReferences.isEmpty()) {
            populateLogReferences();
        }

        return logReferences;
    }

    @Override
    public String getOrigin() {
        return ORIGIN;
    }

    /**
     * Determine equality of plugins using origin to uniquely identify them
     */
    @Override
    public boolean equals(@Nullable Object o) {
        if (!(o instanceof Plugin)) { return false; }
        return this.getOrigin().equals(((Plugin) o).getOrigin());
    }

    /**
     * Hash plugin object using origin to uniquely identify them
     */
    @Override
    public int hashCode() {
        return this.getOrigin().hashCode();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy