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

datadog.trace.api.Config Maven / Gradle / Ivy

There is a newer version: 0.48.0-sfx8
Show newest version
// Modified by SignalFx
package datadog.trace.api;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.UUID;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
 * Config reads values with the following priority: 1) system properties, 2) environment variables,
 * 3) optional configuration file. It also includes default values to ensure a valid config.
 *
 * 

* *

System properties are {@link Config#PREFIX}'ed. Environment variables are the same as the * system property, but uppercased with '.' -> '_'. */ @Slf4j @ToString(includeFieldNames = true) public class Config { /** Config keys below */ private static final String PREFIX = "dd."; private static final String SIGNALFX_PREFIX = "signalfx."; private static final Pattern ENV_REPLACEMENT = Pattern.compile("[^a-zA-Z0-9_]"); public static final String CONFIGURATION_FILE = "trace.config"; public static final String SERVICE_NAME = "service.name"; public static final String TRACE_ENABLED = "tracing.enabled"; public static final String INTEGRATIONS_ENABLED = "integrations.enabled"; public static final String WRITER_TYPE = "writer.type"; public static final String API_TYPE = "api.type"; public static final String USE_B3_PROPAGATION = "b3.propagation"; public static final String AGENT_HOST = "agent.host"; public static final String TRACE_AGENT_PORT = "trace.agent.port"; public static final String AGENT_PORT_LEGACY = "agent.port"; public static final String AGENT_PATH = "agent.path"; public static final String AGENT_USE_HTTPS = "agent.https"; public static final String ENDPOINT_URL = "endpoint.url"; public static final String AGENT_UNIX_DOMAIN_SOCKET = "trace.agent.unix.domain.socket"; public static final String PRIORITY_SAMPLING = "priority.sampling"; public static final String TRACE_RESOLVER_ENABLED = "trace.resolver.enabled"; public static final String SERVICE_MAPPING = "service.mapping"; public static final String GLOBAL_TAGS = "trace.global.tags"; public static final String SPAN_TAGS = "span.tags"; public static final String JMX_TAGS = "trace.jmx.tags"; public static final String TRACE_ANALYTICS_ENABLED = "trace.analytics.enabled"; public static final String TRACE_ANNOTATIONS = "trace.annotations"; public static final String ANNOTATED_METHOD_BLACKLIST = "trace.annotated.method.blacklist"; public static final String TRACE_EXECUTORS_ALL = "trace.executors.all"; public static final String TRACE_EXECUTORS = "trace.executors"; public static final String TRACE_METHODS = "trace.methods"; public static final String TRACE_CLASSES_EXCLUDE = "trace.classes.exclude"; public static final String TRACE_REPORT_HOSTNAME = "trace.report-hostname"; public static final String HEADER_TAGS = "trace.header.tags"; public static final String HTTP_SERVER_ERROR_STATUSES = "http.server.error.statuses"; public static final String HTTP_CLIENT_ERROR_STATUSES = "http.client.error.statuses"; public static final String HTTP_SERVER_TAG_QUERY_STRING = "http.server.tag.query-string"; public static final String HTTP_CLIENT_TAG_QUERY_STRING = "http.client.tag.query-string"; public static final String HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN = "trace.http.client.split-by-domain"; public static final String DB_CLIENT_HOST_SPLIT_BY_INSTANCE = "trace.db.client.split-by-instance"; public static final String SPLIT_BY_TAGS = "trace.split-by-tags"; public static final String PARTIAL_FLUSH_MIN_SPANS = "trace.partial.flush.min.spans"; public static final String RUNTIME_CONTEXT_FIELD_INJECTION = "trace.runtime.context.field.injection"; public static final String PROPAGATION_STYLE_EXTRACT = "propagation.style.extract"; public static final String PROPAGATION_STYLE_INJECT = "propagation.style.inject"; public static final String KAFKA_ATTEMPT_PROPAGATION = "instrumentation.kafka.attempt-propagation"; public static final String REDIS_CAPTURE_COMMAND_ARGUMENTS = "instrumentation.redis.capture-command-arguments"; public static final String ZIPKIN_GZIP_CONTENT_ENCODING = "zipkin.gzip.content.encoding"; public static final String JMX_FETCH_ENABLED = "jmxfetch.enabled"; public static final String JMX_FETCH_CONFIG_DIR = "jmxfetch.config.dir"; public static final String JMX_FETCH_CONFIG = "jmxfetch.config"; public static final String JMX_FETCH_METRICS_CONFIGS = "jmxfetch.metrics-configs"; public static final String JMX_FETCH_CHECK_PERIOD = "jmxfetch.check-period"; public static final String JMX_FETCH_REFRESH_BEANS_PERIOD = "jmxfetch.refresh-beans-period"; public static final String JMX_FETCH_STATSD_HOST = "jmxfetch.statsd.host"; public static final String JMX_FETCH_STATSD_PORT = "jmxfetch.statsd.port"; public static final String HEALTH_METRICS_ENABLED = "trace.health.metrics.enabled"; public static final String HEALTH_METRICS_STATSD_HOST = "trace.health.metrics.statsd.host"; public static final String HEALTH_METRICS_STATSD_PORT = "trace.health.metrics.statsd.port"; public static final String LOGS_INJECTION_ENABLED = "logs.injection"; public static final String DB_STATEMENT_MAX_LENGTH = "db.statement.max.length"; public static final String RECORDED_VALUE_MAX_LENGTH = "recorded.value.max.length"; public static final String SERVICE_TAG = "service"; @Deprecated public static final String SERVICE = SERVICE_TAG; // To be removed in 0.34.0 public static final String RUNTIME_ID_TAG = "runtime-id"; public static final String LANGUAGE_TAG_KEY = "language"; public static final String LANGUAGE_TAG_VALUE = "jvm"; public static final String MAX_SPANS_PER_TRACE = "max.spans.per.trace"; public static final Integer DEFAULT_MAX_SPANS_PER_TRACE = 0; public static final String MAX_CONTINUATION_DEPTH = "max.continuation.depth"; public static final Integer DEFAULT_MAX_CONTINUATION_DEPTH = 100; public static final String DEFAULT_SERVICE_NAME = "unnamed-java-app"; public static final String TRACING_LIBRARY_KEY = "signalfx.tracing.library"; public static final String TRACING_LIBRARY_VALUE = "java-tracing"; public static final String TRACING_VERSION_KEY = "signalfx.tracing.version"; public static final String TRACING_VERSION_VALUE = "0.36.0-sfx10"; private static final boolean DEFAULT_TRACE_ENABLED = true; public static final boolean DEFAULT_INTEGRATIONS_ENABLED = true; public static final String DD_AGENT_WRITER_TYPE = "DDAgentWriter"; public static final String DD_AGENT_API_TYPE = "DD"; public static final String ZIPKIN_V2_API_TYPE = "ZipkinV2"; public static final String LOGGING_WRITER_TYPE = "LoggingWriter"; private static final String DEFAULT_AGENT_WRITER_TYPE = DD_AGENT_WRITER_TYPE; public static final String DEFAULT_API_TYPE = ZIPKIN_V2_API_TYPE; public static final String DEFAULT_AGENT_ENDPOINT = "http://localhost:9080/v1/trace"; public static final String DEFAULT_AGENT_UNIX_DOMAIN_SOCKET = null; private static final boolean DEFAULT_RUNTIME_CONTEXT_FIELD_INJECTION = true; private static final boolean DEFAULT_PRIORITY_SAMPLING_ENABLED = false; private static final boolean DEFAULT_TRACE_RESOLVER_ENABLED = true; private static final Set DEFAULT_HTTP_SERVER_ERROR_STATUSES = parseIntegerRangeSet("500-599", "default"); private static final Set DEFAULT_HTTP_CLIENT_ERROR_STATUSES = parseIntegerRangeSet("500-599", "default"); private static final boolean DEFAULT_HTTP_SERVER_TAG_QUERY_STRING = false; private static final boolean DEFAULT_HTTP_CLIENT_TAG_QUERY_STRING = false; private static final boolean DEFAULT_HTTP_CLIENT_SPLIT_BY_DOMAIN = false; private static final boolean DEFAULT_DB_CLIENT_HOST_SPLIT_BY_INSTANCE = false; private static final String DEFAULT_SPLIT_BY_TAGS = ""; public static final int DEFAULT_PARTIAL_FLUSH_MIN_SPANS = 1000; private static final String DEFAULT_PROPAGATION_STYLE_EXTRACT = PropagationStyle.B3.name(); private static final String DEFAULT_PROPAGATION_STYLE_INJECT = PropagationStyle.B3.name(); private static final boolean DEFAULT_JMX_FETCH_ENABLED = false; public static final boolean DEFAULT_KAFKA_ATTEMPT_PROPAGATION = true; public static final boolean DEFAULT_REDIS_CAPTURE_COMMAND_ARGUMENTS = true; public static final int DEFAULT_JMX_FETCH_STATSD_PORT = 8125; public static final boolean DEFAULT_METRICS_ENABLED = false; // No default constants for metrics statsd support -- falls back to jmx fetch values public static final boolean DEFAULT_LOGS_INJECTION_ENABLED = false; private static final String SPLIT_BY_SPACE_OR_COMMA_REGEX = "[,\\s]+"; private static final boolean DEFAULT_TRACE_REPORT_HOSTNAME = false; private static final String DEFAULT_TRACE_ANNOTATIONS = null; private static final String DEFAULT_ANNOTATED_METHOD_BLACKLIST = null; private static final boolean DEFAULT_TRACE_EXECUTORS_ALL = false; private static final String DEFAULT_TRACE_EXECUTORS = ""; private static final String DEFAULT_TRACE_METHODS = null; public static final boolean DEFAULT_TRACE_ANALYTICS_ENABLED = false; public static final float DEFAULT_ANALYTICS_SAMPLE_RATE = 1.0f; public enum PropagationStyle { DATADOG, B3, HAYSTACK } public static final int DEFAULT_DB_STATEMENT_MAX_LENGTH = 1024; public static final int DEFAULT_RECORDED_VALUE_MAX_LENGTH = 12288; public static final boolean DEFAULT_ZIPKIN_GZIP_CONTENT_ENCODING = true; /** A tag intended for internal use only, hence not added to the public api DDTags class. */ private static final String INTERNAL_HOST_NAME = "_dd.hostname"; /** * this is a random UUID that gets generated on JVM start up and is attached to every root span * and every JMX metric that is sent out. */ @Getter private final String runtimeId; @Getter private final String serviceName; @Getter private final boolean traceEnabled; @Getter private final boolean integrationsEnabled; @Getter private final String writerType; @Getter private final String apiType; @Getter private final boolean useB3Propagation; private final String agentHost; private final Integer agentPort; private final String agentPath; private final Boolean agentUseHTTPS; @Getter private final URL endpointUrl; @Getter private final String agentUnixDomainSocket; @Getter private final boolean prioritySamplingEnabled; @Getter private final boolean traceResolverEnabled; @Getter private final Map serviceMapping; private final Map globalTags; private final Map spanTags; private final Map jmxTags; @Getter private final List excludedClasses; @Getter private final Map headerTags; @Getter private final Set httpServerErrorStatuses; @Getter private final Set httpClientErrorStatuses; @Getter private final boolean httpServerTagQueryString; @Getter private final boolean httpClientTagQueryString; @Getter private final boolean httpClientSplitByDomain; @Getter private final boolean dbClientSplitByInstance; @Getter private final Set splitByTags; @Getter private final Integer partialFlushMinSpans; @Getter private final boolean runtimeContextFieldInjection; @Getter private final Set propagationStylesToExtract; @Getter private final Set propagationStylesToInject; @Getter private final boolean kafkaAttemptPropagation; @Getter private final boolean redisCaptureCommandArguments; @Getter private final boolean zipkinGZIPContentEncoding; @Getter private final boolean jmxFetchEnabled; @Getter private final String jmxFetchConfigDir; @Getter private final List jmxFetchConfigs; @Deprecated @Getter private final List jmxFetchMetricsConfigs; @Getter private final Integer jmxFetchCheckPeriod; @Getter private final Integer jmxFetchRefreshBeansPeriod; @Getter private final String jmxFetchStatsdHost; @Getter private final Integer jmxFetchStatsdPort; // These values are default-ed to those of jmx fetch values as needed @Getter private final boolean healthMetricsEnabled; @Getter private final String healthMetricsStatsdHost; @Getter private final Integer healthMetricsStatsdPort; @Getter private final boolean logsInjectionEnabled; @Getter private final boolean reportHostName; @Getter private final Integer dbStatementMaxLength; @Getter private final Integer recordedValueMaxLength; // Read order: System Properties -> Env Variables, [-> default value] @Getter private final String traceAnnotations; @Getter private final String annotatedMethodBlacklist; @Getter private final String traceMethods; @Getter private final boolean traceExecutorsAll; @Getter private final List traceExecutors; @Getter private final boolean traceAnalyticsEnabled; @Getter private final Integer maxSpansPerTrace; @Getter private final Integer maxContinuationDepth; // Values from an optionally provided properties file private static Properties propertiesFromConfigFile; // Read order: System Properties -> Env Variables, [-> properties file], [-> default value] // Visible for testing Config() { propertiesFromConfigFile = loadConfigurationFile(); runtimeId = UUID.randomUUID().toString(); serviceName = getSettingFromEnvironment(SERVICE_NAME, DEFAULT_SERVICE_NAME); traceEnabled = getBooleanSettingFromEnvironment(TRACE_ENABLED, DEFAULT_TRACE_ENABLED); integrationsEnabled = getBooleanSettingFromEnvironment(INTEGRATIONS_ENABLED, DEFAULT_INTEGRATIONS_ENABLED); writerType = getSettingFromEnvironment(WRITER_TYPE, DEFAULT_AGENT_WRITER_TYPE); apiType = getSettingFromEnvironment(API_TYPE, DEFAULT_API_TYPE); useB3Propagation = getBooleanSettingFromEnvironment(USE_B3_PROPAGATION, true); agentHost = getSettingFromEnvironment(AGENT_HOST, null); agentPort = getIntegerSettingFromEnvironment( TRACE_AGENT_PORT, getIntegerSettingFromEnvironment(AGENT_PORT_LEGACY, null)); agentPath = getSettingFromEnvironment(AGENT_PATH, null); agentUseHTTPS = getBooleanSettingFromEnvironment(AGENT_USE_HTTPS, null); endpointUrl = getURLSettingFromEnvironment(ENDPOINT_URL, DEFAULT_AGENT_ENDPOINT); agentUnixDomainSocket = getSettingFromEnvironment(AGENT_UNIX_DOMAIN_SOCKET, DEFAULT_AGENT_UNIX_DOMAIN_SOCKET); prioritySamplingEnabled = getBooleanSettingFromEnvironment(PRIORITY_SAMPLING, DEFAULT_PRIORITY_SAMPLING_ENABLED); traceResolverEnabled = getBooleanSettingFromEnvironment(TRACE_RESOLVER_ENABLED, DEFAULT_TRACE_RESOLVER_ENABLED); serviceMapping = getMapSettingFromEnvironment(SERVICE_MAPPING, null); globalTags = getMapSettingFromEnvironment(GLOBAL_TAGS, null); spanTags = getMapSettingFromEnvironment(SPAN_TAGS, null); jmxTags = getMapSettingFromEnvironment(JMX_TAGS, null); excludedClasses = getListSettingFromEnvironment(TRACE_CLASSES_EXCLUDE, null); headerTags = getMapSettingFromEnvironment(HEADER_TAGS, null); httpServerErrorStatuses = getIntegerRangeSettingFromEnvironment( HTTP_SERVER_ERROR_STATUSES, DEFAULT_HTTP_SERVER_ERROR_STATUSES); httpClientErrorStatuses = getIntegerRangeSettingFromEnvironment( HTTP_CLIENT_ERROR_STATUSES, DEFAULT_HTTP_CLIENT_ERROR_STATUSES); httpServerTagQueryString = getBooleanSettingFromEnvironment( HTTP_SERVER_TAG_QUERY_STRING, DEFAULT_HTTP_SERVER_TAG_QUERY_STRING); httpClientTagQueryString = getBooleanSettingFromEnvironment( HTTP_CLIENT_TAG_QUERY_STRING, DEFAULT_HTTP_CLIENT_TAG_QUERY_STRING); httpClientSplitByDomain = getBooleanSettingFromEnvironment( HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, DEFAULT_HTTP_CLIENT_SPLIT_BY_DOMAIN); dbClientSplitByInstance = getBooleanSettingFromEnvironment( DB_CLIENT_HOST_SPLIT_BY_INSTANCE, DEFAULT_DB_CLIENT_HOST_SPLIT_BY_INSTANCE); splitByTags = Collections.unmodifiableSet( new LinkedHashSet<>( getListSettingFromEnvironment(SPLIT_BY_TAGS, DEFAULT_SPLIT_BY_TAGS))); partialFlushMinSpans = getIntegerSettingFromEnvironment(PARTIAL_FLUSH_MIN_SPANS, DEFAULT_PARTIAL_FLUSH_MIN_SPANS); runtimeContextFieldInjection = getBooleanSettingFromEnvironment( RUNTIME_CONTEXT_FIELD_INJECTION, DEFAULT_RUNTIME_CONTEXT_FIELD_INJECTION); propagationStylesToExtract = getEnumSetSettingFromEnvironment( PROPAGATION_STYLE_EXTRACT, DEFAULT_PROPAGATION_STYLE_EXTRACT, PropagationStyle.class, true); propagationStylesToInject = getEnumSetSettingFromEnvironment( PROPAGATION_STYLE_INJECT, DEFAULT_PROPAGATION_STYLE_INJECT, PropagationStyle.class, true); kafkaAttemptPropagation = getBooleanSettingFromEnvironment( KAFKA_ATTEMPT_PROPAGATION, DEFAULT_KAFKA_ATTEMPT_PROPAGATION); redisCaptureCommandArguments = getBooleanSettingFromEnvironment( REDIS_CAPTURE_COMMAND_ARGUMENTS, DEFAULT_REDIS_CAPTURE_COMMAND_ARGUMENTS); zipkinGZIPContentEncoding = getBooleanSettingFromEnvironment( ZIPKIN_GZIP_CONTENT_ENCODING, DEFAULT_ZIPKIN_GZIP_CONTENT_ENCODING); jmxFetchEnabled = getBooleanSettingFromEnvironment(JMX_FETCH_ENABLED, DEFAULT_JMX_FETCH_ENABLED); jmxFetchConfigDir = getSettingFromEnvironment(JMX_FETCH_CONFIG_DIR, null); jmxFetchConfigs = getListSettingFromEnvironment(JMX_FETCH_CONFIG, null); jmxFetchMetricsConfigs = getListSettingFromEnvironment(JMX_FETCH_METRICS_CONFIGS, null); jmxFetchCheckPeriod = getIntegerSettingFromEnvironment(JMX_FETCH_CHECK_PERIOD, null); jmxFetchRefreshBeansPeriod = getIntegerSettingFromEnvironment(JMX_FETCH_REFRESH_BEANS_PERIOD, null); jmxFetchStatsdHost = getSettingFromEnvironment(JMX_FETCH_STATSD_HOST, null); jmxFetchStatsdPort = getIntegerSettingFromEnvironment(JMX_FETCH_STATSD_PORT, DEFAULT_JMX_FETCH_STATSD_PORT); // Writer.Builder createMonitor will use the values of the JMX fetch & agent to fill-in defaults healthMetricsEnabled = getBooleanSettingFromEnvironment(HEALTH_METRICS_ENABLED, DEFAULT_METRICS_ENABLED); healthMetricsStatsdHost = getSettingFromEnvironment(HEALTH_METRICS_STATSD_HOST, null); healthMetricsStatsdPort = getIntegerSettingFromEnvironment(HEALTH_METRICS_STATSD_PORT, null); logsInjectionEnabled = getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED); reportHostName = getBooleanSettingFromEnvironment(TRACE_REPORT_HOSTNAME, DEFAULT_TRACE_REPORT_HOSTNAME); dbStatementMaxLength = getIntegerSettingFromEnvironment(DB_STATEMENT_MAX_LENGTH, DEFAULT_DB_STATEMENT_MAX_LENGTH); recordedValueMaxLength = getIntegerSettingFromEnvironment( RECORDED_VALUE_MAX_LENGTH, DEFAULT_RECORDED_VALUE_MAX_LENGTH); traceAnnotations = getSettingFromEnvironment(TRACE_ANNOTATIONS, DEFAULT_TRACE_ANNOTATIONS); annotatedMethodBlacklist = getSettingFromEnvironment(ANNOTATED_METHOD_BLACKLIST, DEFAULT_ANNOTATED_METHOD_BLACKLIST); traceMethods = getSettingFromEnvironment(TRACE_METHODS, DEFAULT_TRACE_METHODS); traceExecutorsAll = getBooleanSettingFromEnvironment(TRACE_EXECUTORS_ALL, DEFAULT_TRACE_EXECUTORS_ALL); traceExecutors = getListSettingFromEnvironment(TRACE_EXECUTORS, DEFAULT_TRACE_EXECUTORS); traceAnalyticsEnabled = getBooleanSettingFromEnvironment(TRACE_ANALYTICS_ENABLED, DEFAULT_TRACE_ANALYTICS_ENABLED); maxSpansPerTrace = getIntegerSettingFromEnvironment(MAX_SPANS_PER_TRACE, DEFAULT_MAX_SPANS_PER_TRACE); maxContinuationDepth = getIntegerSettingFromEnvironment(MAX_CONTINUATION_DEPTH, DEFAULT_MAX_CONTINUATION_DEPTH); log.debug("New instance: {}", this); } // Read order: Properties -> Parent private Config(final Properties properties, final Config parent) { runtimeId = parent.runtimeId; serviceName = properties.getProperty(SERVICE_NAME, parent.serviceName); traceEnabled = getPropertyBooleanValue(properties, TRACE_ENABLED, parent.traceEnabled); integrationsEnabled = getPropertyBooleanValue(properties, INTEGRATIONS_ENABLED, parent.integrationsEnabled); writerType = properties.getProperty(WRITER_TYPE, parent.writerType); apiType = properties.getProperty(API_TYPE, parent.apiType); useB3Propagation = getPropertyBooleanValue(properties, USE_B3_PROPAGATION, parent.useB3Propagation); agentHost = properties.getProperty(AGENT_HOST, parent.agentHost); agentPort = getPropertyIntegerValue( properties, TRACE_AGENT_PORT, getPropertyIntegerValue(properties, AGENT_PORT_LEGACY, parent.agentPort)); agentPath = properties.getProperty(AGENT_PATH, parent.agentPath); agentUseHTTPS = getPropertyBooleanValue(properties, AGENT_USE_HTTPS, parent.agentUseHTTPS); endpointUrl = getPropertyURLValue(properties, ENDPOINT_URL, parent.endpointUrl); agentUnixDomainSocket = properties.getProperty(AGENT_UNIX_DOMAIN_SOCKET, parent.agentUnixDomainSocket); prioritySamplingEnabled = getPropertyBooleanValue(properties, PRIORITY_SAMPLING, parent.prioritySamplingEnabled); traceResolverEnabled = getPropertyBooleanValue(properties, TRACE_RESOLVER_ENABLED, parent.traceResolverEnabled); serviceMapping = getPropertyMapValue(properties, SERVICE_MAPPING, parent.serviceMapping); globalTags = getPropertyMapValue(properties, GLOBAL_TAGS, parent.globalTags); spanTags = getPropertyMapValue(properties, SPAN_TAGS, parent.spanTags); jmxTags = getPropertyMapValue(properties, JMX_TAGS, parent.jmxTags); excludedClasses = getPropertyListValue(properties, TRACE_CLASSES_EXCLUDE, parent.excludedClasses); headerTags = getPropertyMapValue(properties, HEADER_TAGS, parent.headerTags); httpServerErrorStatuses = getPropertyIntegerRangeValue( properties, HTTP_SERVER_ERROR_STATUSES, parent.httpServerErrorStatuses); httpClientErrorStatuses = getPropertyIntegerRangeValue( properties, HTTP_CLIENT_ERROR_STATUSES, parent.httpClientErrorStatuses); httpServerTagQueryString = getPropertyBooleanValue( properties, HTTP_SERVER_TAG_QUERY_STRING, parent.httpServerTagQueryString); httpClientTagQueryString = getPropertyBooleanValue( properties, HTTP_CLIENT_TAG_QUERY_STRING, parent.httpClientTagQueryString); httpClientSplitByDomain = getPropertyBooleanValue( properties, HTTP_CLIENT_HOST_SPLIT_BY_DOMAIN, parent.httpClientSplitByDomain); dbClientSplitByInstance = getPropertyBooleanValue( properties, DB_CLIENT_HOST_SPLIT_BY_INSTANCE, parent.dbClientSplitByInstance); splitByTags = Collections.unmodifiableSet( new LinkedHashSet<>( getPropertyListValue( properties, SPLIT_BY_TAGS, new ArrayList<>(parent.splitByTags)))); partialFlushMinSpans = getPropertyIntegerValue(properties, PARTIAL_FLUSH_MIN_SPANS, parent.partialFlushMinSpans); runtimeContextFieldInjection = getPropertyBooleanValue( properties, RUNTIME_CONTEXT_FIELD_INJECTION, parent.runtimeContextFieldInjection); final Set parsedPropagationStylesToExtract = getPropertySetValue(properties, PROPAGATION_STYLE_EXTRACT, PropagationStyle.class); propagationStylesToExtract = parsedPropagationStylesToExtract == null ? parent.propagationStylesToExtract : parsedPropagationStylesToExtract; final Set parsedPropagationStylesToInject = getPropertySetValue(properties, PROPAGATION_STYLE_INJECT, PropagationStyle.class); propagationStylesToInject = parsedPropagationStylesToInject == null ? parent.propagationStylesToInject : parsedPropagationStylesToInject; kafkaAttemptPropagation = getPropertyBooleanValue( properties, KAFKA_ATTEMPT_PROPAGATION, parent.kafkaAttemptPropagation); redisCaptureCommandArguments = getPropertyBooleanValue( properties, REDIS_CAPTURE_COMMAND_ARGUMENTS, parent.redisCaptureCommandArguments); zipkinGZIPContentEncoding = getPropertyBooleanValue( properties, ZIPKIN_GZIP_CONTENT_ENCODING, parent.zipkinGZIPContentEncoding); jmxFetchEnabled = getPropertyBooleanValue(properties, JMX_FETCH_ENABLED, parent.jmxFetchEnabled); jmxFetchConfigDir = properties.getProperty(JMX_FETCH_CONFIG_DIR, parent.jmxFetchConfigDir); jmxFetchConfigs = getPropertyListValue(properties, JMX_FETCH_CONFIG, parent.jmxFetchConfigs); jmxFetchMetricsConfigs = getPropertyListValue(properties, JMX_FETCH_METRICS_CONFIGS, parent.jmxFetchMetricsConfigs); jmxFetchCheckPeriod = getPropertyIntegerValue(properties, JMX_FETCH_CHECK_PERIOD, parent.jmxFetchCheckPeriod); jmxFetchRefreshBeansPeriod = getPropertyIntegerValue( properties, JMX_FETCH_REFRESH_BEANS_PERIOD, parent.jmxFetchRefreshBeansPeriod); jmxFetchStatsdHost = properties.getProperty(JMX_FETCH_STATSD_HOST, parent.jmxFetchStatsdHost); jmxFetchStatsdPort = getPropertyIntegerValue(properties, JMX_FETCH_STATSD_PORT, parent.jmxFetchStatsdPort); healthMetricsEnabled = getPropertyBooleanValue(properties, HEALTH_METRICS_ENABLED, DEFAULT_METRICS_ENABLED); healthMetricsStatsdHost = properties.getProperty(HEALTH_METRICS_STATSD_HOST, parent.healthMetricsStatsdHost); healthMetricsStatsdPort = getPropertyIntegerValue( properties, HEALTH_METRICS_STATSD_PORT, parent.healthMetricsStatsdPort); logsInjectionEnabled = getBooleanSettingFromEnvironment(LOGS_INJECTION_ENABLED, DEFAULT_LOGS_INJECTION_ENABLED); reportHostName = getPropertyBooleanValue(properties, TRACE_REPORT_HOSTNAME, parent.reportHostName); dbStatementMaxLength = getPropertyIntegerValue(properties, DB_STATEMENT_MAX_LENGTH, parent.dbStatementMaxLength); recordedValueMaxLength = getPropertyIntegerValue( properties, RECORDED_VALUE_MAX_LENGTH, parent.recordedValueMaxLength); traceAnnotations = properties.getProperty(TRACE_ANNOTATIONS, parent.traceAnnotations); annotatedMethodBlacklist = properties.getProperty(ANNOTATED_METHOD_BLACKLIST, parent.annotatedMethodBlacklist); traceMethods = properties.getProperty(TRACE_METHODS, parent.traceMethods); traceExecutorsAll = getPropertyBooleanValue(properties, TRACE_EXECUTORS_ALL, parent.traceExecutorsAll); traceExecutors = getPropertyListValue(properties, TRACE_EXECUTORS, parent.traceExecutors); traceAnalyticsEnabled = getPropertyBooleanValue(properties, TRACE_ANALYTICS_ENABLED, parent.traceAnalyticsEnabled); maxSpansPerTrace = getPropertyIntegerValue(properties, MAX_SPANS_PER_TRACE, DEFAULT_MAX_SPANS_PER_TRACE); maxContinuationDepth = getPropertyIntegerValue(properties, MAX_CONTINUATION_DEPTH, DEFAULT_MAX_CONTINUATION_DEPTH); log.debug("New instance: {}", this); } /** @return A map of tags to be applied only to the local application root span. */ public Map getLocalRootSpanTags() { final Map runtimeTags = getRuntimeTags(); final Map result = new HashMap<>(runtimeTags); result.put(TRACING_LIBRARY_KEY, TRACING_LIBRARY_VALUE); result.put(TRACING_VERSION_KEY, TRACING_VERSION_VALUE); if (reportHostName) { final String hostName = getHostName(); if (null != hostName && !hostName.isEmpty()) { result.put(INTERNAL_HOST_NAME, hostName); } } return Collections.unmodifiableMap(result); } public String getAgentHost() { if (agentHost != null) { return agentHost; } return endpointUrl == null ? null : endpointUrl.getHost(); } public Integer getAgentPort() { if (agentPort != null) { return agentPort; } return endpointUrl == null ? null : endpointUrl.getPort(); } public Boolean getAgentUseHTTPS() { if (agentUseHTTPS != null) { return agentUseHTTPS; } return endpointUrl == null ? null : "https".equals(endpointUrl.getProtocol()); } public String getAgentPath() { if (agentPath != null) { return agentPath; } return endpointUrl == null ? null : endpointUrl.getPath(); } public Map getMergedSpanTags() { // DO not include runtimeId into span tags: we only want that added to the root span final Map result = newHashMap(globalTags.size() + spanTags.size()); result.putAll(globalTags); result.putAll(spanTags); return Collections.unmodifiableMap(result); } public Map getMergedJmxTags() { final Map runtimeTags = getRuntimeTags(); final Map result = newHashMap( globalTags.size() + jmxTags.size() + runtimeTags.size() + 1 /* for serviceName */); result.putAll(globalTags); result.putAll(jmxTags); result.putAll(runtimeTags); // service name set here instead of getRuntimeTags because apm already manages the service tag // and may chose to override it. // Additionally, infra/JMX metrics require `service` rather than APM's `service.name` tag result.put(SERVICE_TAG, serviceName); return Collections.unmodifiableMap(result); } /** * Returns the sample rate for the specified instrumentation or {@link * #DEFAULT_ANALYTICS_SAMPLE_RATE} if none specified. */ public float getInstrumentationAnalyticsSampleRate(final String... aliases) { for (final String alias : aliases) { final Float rate = getFloatSettingFromEnvironment(alias + ".analytics.sample-rate", null); if (null != rate) { return rate; } } return DEFAULT_ANALYTICS_SAMPLE_RATE; } /** * Return a map of tags required by the datadog backend to link runtime metrics (i.e. jmx) and * traces. * *

These tags must be applied to every runtime metrics and placed on the root span of every * trace. * * @return A map of tag-name -> tag-value */ private Map getRuntimeTags() { // Rather than attempt to strip these on Zipkin encoding, do not use any // undesired runtime tags to prevent collisions final Map result = newHashMap(0); return Collections.unmodifiableMap(result); } public boolean isIntegrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { return integrationEnabled(integrationNames, defaultEnabled); } /** * @deprecated This method should only be used internally. Use the instance getter instead {@link * #isIntegrationEnabled(SortedSet, boolean)}. * @param integrationNames * @param defaultEnabled * @return */ public static boolean integrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { // If default is enabled, we want to enable individually, // if default is disabled, we want to disable individually. boolean anyEnabled = defaultEnabled; for (final String name : integrationNames) { final boolean configEnabled = getBooleanSettingFromEnvironment("integration." + name + ".enabled", defaultEnabled); if (defaultEnabled) { anyEnabled &= configEnabled; } else { anyEnabled |= configEnabled; } } return anyEnabled; } public boolean isJmxFetchIntegrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { return jmxFetchIntegrationEnabled(integrationNames, defaultEnabled); } /** * @deprecated This method should only be used internally. Use the instance getter instead {@link * #isJmxFetchIntegrationEnabled(SortedSet, boolean)}. * @param integrationNames * @param defaultEnabled * @return */ public static boolean jmxFetchIntegrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { // If default is enabled, we want to enable individually, // if default is disabled, we want to disable individually. boolean anyEnabled = defaultEnabled; for (final String name : integrationNames) { final boolean configEnabled = getBooleanSettingFromEnvironment("jmxfetch." + name + ".enabled", defaultEnabled); if (defaultEnabled) { anyEnabled &= configEnabled; } else { anyEnabled |= configEnabled; } } return anyEnabled; } public boolean isTraceAnalyticsIntegrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { return traceAnalyticsIntegrationEnabled(integrationNames, defaultEnabled); } /** * @deprecated This method should only be used internally. Use the instance getter instead {@link * #isTraceAnalyticsIntegrationEnabled(SortedSet, boolean)}. * @param integrationNames * @param defaultEnabled * @return */ public static boolean traceAnalyticsIntegrationEnabled( final SortedSet integrationNames, final boolean defaultEnabled) { // If default is enabled, we want to enable individually, // if default is disabled, we want to disable individually. boolean anyEnabled = defaultEnabled; for (final String name : integrationNames) { final boolean configEnabled = getBooleanSettingFromEnvironment(name + ".analytics.enabled", defaultEnabled); if (defaultEnabled) { anyEnabled &= configEnabled; } else { anyEnabled |= configEnabled; } } return anyEnabled; } /** * Helper method that takes the name, adds a "signalfx." prefix then checks for System Properties * of that name. If none found, the name is converted to an Environment Variable and used to check * the env. If none of the above returns a value, then an optional properties file if checked. If * setting is not configured in either location, the process repeats with the "dd." prefix. If no * subsequent mtach, defaultValue is returned. * * @param name * @param defaultValue * @return * @deprecated This method should only be used internally. Use the explicit getter instead. */ public static String getSettingFromEnvironment(final String name, final String defaultValue) { String value = getSettingFromEnvironment(SIGNALFX_PREFIX, name, null); if (value == null) { // Let the original prefix act as a fallback so we support both for testing/migration // purposes. value = getSettingFromEnvironment(PREFIX, name, null); } String returned = value == null ? defaultValue : value; return returned; } public static String getSettingFromEnvironment( final String prefix, final String name, final String defaultValue) { String propertyName = propertyNameToSystemPropertyName(prefix, name); String value = null; // System properties and properties provided from command line have the highest precedence value = System.getProperties().getProperty(propertyName); if (null != value) { return value; } // If value not provided from system properties, looking at env variables value = System.getenv(propertyNameToEnvironmentVariableName(prefix, name)); if (null != value) { return value; } // If value is not defined yet, we look at properties optionally defined in a properties file value = propertiesFromConfigFile.getProperty(propertyName); return value; } /** @deprecated This method should only be used internally. Use the explicit getter instead. */ private static Map getMapSettingFromEnvironment( final String name, final String defaultValue) { return parseMap( getSettingFromEnvironment(name, defaultValue), propertyNameToSystemPropertyName(name)); } /** * Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a list by * splitting on `,`. * * @deprecated This method should only be used internally. Use the explicit getter instead. */ public static List getListSettingFromEnvironment( final String name, final String defaultValue) { return parseList(getSettingFromEnvironment(name, defaultValue)); } private static URL getURLSettingFromEnvironment(final String name, final String defaultValue) { return parseURL(getSettingFromEnvironment(name, defaultValue), name); } /** * Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a Boolean. * * @deprecated This method should only be used internally. Use the explicit getter instead. */ public static Boolean getBooleanSettingFromEnvironment( final String name, final Boolean defaultValue) { final String value = getSettingFromEnvironment(name, null); return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value); } /** * Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a Float. * * @deprecated This method should only be used internally. Use the explicit getter instead. */ public static Float getFloatSettingFromEnvironment(final String name, final Float defaultValue) { final String value = getSettingFromEnvironment(name, null); try { return value == null ? defaultValue : Float.valueOf(value); } catch (final NumberFormatException e) { log.warn("Invalid configuration for " + name, e); return defaultValue; } } /** * Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a Integer. */ private static Integer getIntegerSettingFromEnvironment( final String name, final Integer defaultValue) { final String value = getSettingFromEnvironment(name, null); try { return value == null ? defaultValue : Integer.valueOf(value); } catch (final NumberFormatException e) { log.warn("Invalid configuration for " + name, e); return defaultValue; } } /** * Calls {@link #getSettingFromEnvironment(String, String)} and converts the result to a set of * strings splitting by space or comma. */ private static > Set getEnumSetSettingFromEnvironment( final String name, final String defaultValue, final Class clazz, final boolean emptyResultMeansUseDefault) { final String value = getSettingFromEnvironment(name, defaultValue); Set result = convertStringSetToEnumSet( parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz); if (emptyResultMeansUseDefault && result.isEmpty()) { // Treat empty parsing result as no value and use default instead result = convertStringSetToEnumSet( parseStringIntoSetOfNonEmptyStrings(defaultValue, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz); } return result; } private Set getIntegerRangeSettingFromEnvironment( final String name, final Set defaultValue) { final String value = getSettingFromEnvironment(name, null); try { return value == null ? defaultValue : parseIntegerRangeSet(value, name); } catch (final NumberFormatException e) { log.warn("Invalid configuration for " + name, e); return defaultValue; } } /** * Converts the property name, e.g. 'service.name' into a public environment variable name, e.g. * `SIGNALFX_SERVICE_NAME`. * * @param setting The setting name, e.g. `service.name` * @return The public facing environment variable name */ private static String propertyNameToEnvironmentVariableName(final String setting) { return propertyNameToEnvironmentVariableName(SIGNALFX_PREFIX, setting); } private static String propertyNameToEnvironmentVariableName( final String prefix, final String setting) { return ENV_REPLACEMENT .matcher(propertyNameToSystemPropertyName(prefix, setting).toUpperCase()) .replaceAll("_"); } /** * Converts the property name, e.g. 'service.name' into a public system property name, e.g. * `signalfx.service.name`. * * @param setting The setting name, e.g. `service.name` * @return The public facing system property name */ private static String propertyNameToSystemPropertyName(final String setting) { return propertyNameToSystemPropertyName(SIGNALFX_PREFIX, setting); } private static String propertyNameToSystemPropertyName( final String prefix, final String setting) { return prefix + setting; } private static Map getPropertyMapValue( final Properties properties, final String name, final Map defaultValue) { final String value = properties.getProperty(name); return value == null || value.trim().isEmpty() ? defaultValue : parseMap(value, name); } private static List getPropertyListValue( final Properties properties, final String name, final List defaultValue) { final String value = properties.getProperty(name); return value == null || value.trim().isEmpty() ? defaultValue : parseList(value); } private static URL getPropertyURLValue( final Properties properties, final String name, final URL defaultValue) { final String value = properties.getProperty(name); return value == null ? defaultValue : parseURL(value, name); } private static Boolean getPropertyBooleanValue( final Properties properties, final String name, final Boolean defaultValue) { final String value = properties.getProperty(name); return value == null || value.trim().isEmpty() ? defaultValue : Boolean.valueOf(value); } private static Integer getPropertyIntegerValue( final Properties properties, final String name, final Integer defaultValue) { final String value = properties.getProperty(name); return value == null || value.trim().isEmpty() ? defaultValue : Integer.valueOf(value); } private static > Set getPropertySetValue( final Properties properties, final String name, final Class clazz) { final String value = properties.getProperty(name); if (value != null) { final Set result = convertStringSetToEnumSet( parseStringIntoSetOfNonEmptyStrings(value, SPLIT_BY_SPACE_OR_COMMA_REGEX), clazz); if (!result.isEmpty()) { return result; } } // null means parent value should be used return null; } private Set getPropertyIntegerRangeValue( final Properties properties, final String name, final Set defaultValue) { final String value = properties.getProperty(name); try { return value == null ? defaultValue : parseIntegerRangeSet(value, name); } catch (final NumberFormatException e) { log.warn("Invalid configuration for " + name, e); return defaultValue; } } private static Map parseMap(final String str, final String settingName) { // If we ever want to have default values besides an empty map, this will need to change. if (str == null || str.trim().isEmpty()) { return Collections.emptyMap(); } if (!str.matches("(([^,:]+:[^,:]*,)*([^,:]+:[^,:]*),?)?")) { log.warn( "Invalid config for {}: '{}'. Must match 'key1:value1,key2:value2'.", settingName, str); return Collections.emptyMap(); } final String[] tokens = str.split(",", -1); final Map map = newHashMap(tokens.length); for (final String token : tokens) { final String[] keyValue = token.split(":", -1); if (keyValue.length == 2) { final String key = keyValue[0].trim(); final String value = keyValue[1].trim(); if (value.length() <= 0) { log.warn("Ignoring empty value for key '{}' in config for {}", key, settingName); continue; } map.put(key, value); } } return Collections.unmodifiableMap(map); } private static Set parseIntegerRangeSet(String str, final String settingName) throws NumberFormatException { assert str != null; str = str.replaceAll("\\s", ""); if (!str.matches("\\d{3}(?:-\\d{3})?(?:,\\d{3}(?:-\\d{3})?)*")) { log.warn( "Invalid config for {}: '{}'. Must be formatted like '400-403,405,410-499'.", settingName, str); throw new NumberFormatException(); } final String[] tokens = str.split(",", -1); final Set set = new HashSet<>(); for (final String token : tokens) { final String[] range = token.split("-", -1); if (range.length == 1) { set.add(Integer.parseInt(range[0])); } else if (range.length == 2) { final int left = Integer.parseInt(range[0]); final int right = Integer.parseInt(range[1]); final int min = Math.min(left, right); final int max = Math.max(left, right); for (int i = min; i <= max; i++) { set.add(i); } } } return Collections.unmodifiableSet(set); } private static Map newHashMap(final int size) { return new HashMap<>(size + 1, 1f); } private static List parseList(final String str) { if (str == null || str.trim().isEmpty()) { return Collections.emptyList(); } final String[] tokens = str.split(",", -1); // Remove whitespace from each item. for (int i = 0; i < tokens.length; i++) { tokens[i] = tokens[i].trim(); } return Collections.unmodifiableList(Arrays.asList(tokens)); } private static URL parseURL(final String str, final String settingName) { try { return new URL(str); } catch (MalformedURLException e) { log.warn("Malformed URL {} in setting {}: {}", str, settingName, e.getMessage()); return null; } } private static Set parseStringIntoSetOfNonEmptyStrings( final String str, final String regex) { // Using LinkedHashSet to preserve original string order final Set result = new LinkedHashSet<>(); // Java returns single value when splitting an empty string. We do not need that value, so // we need to throw it out. for (final String value : str.split(regex)) { if (!value.isEmpty()) { result.add(value); } } return Collections.unmodifiableSet(result); } private static > Set convertStringSetToEnumSet( final Set input, final Class clazz) { // Using LinkedHashSet to preserve original string order final Set result = new LinkedHashSet<>(); for (final String value : input) { try { result.add(Enum.valueOf(clazz, value.toUpperCase())); } catch (final IllegalArgumentException e) { log.debug("Cannot recognize config string value: {}, {}", value, clazz); } } return Collections.unmodifiableSet(result); } /** * Loads the optional configuration properties file into the global {@link Properties} object. * * @return The {@link Properties} object. the returned instance might be empty of file does not * exist or if it is in a wrong format. */ private static Properties loadConfigurationFile() { final Properties properties = new Properties(); // Reading from system property first and from env after String configurationFilePath = System.getProperty(propertyNameToSystemPropertyName(SIGNALFX_PREFIX, CONFIGURATION_FILE)); if (null == configurationFilePath) { configurationFilePath = System.getenv(propertyNameToEnvironmentVariableName(SIGNALFX_PREFIX, CONFIGURATION_FILE)); } if (null == configurationFilePath) { configurationFilePath = System.getProperty(propertyNameToSystemPropertyName(PREFIX, CONFIGURATION_FILE)); } if (null == configurationFilePath) { configurationFilePath = System.getenv(propertyNameToEnvironmentVariableName(PREFIX, CONFIGURATION_FILE)); } if (null == configurationFilePath) { return properties; } // Normalizing tilde (~) paths for unix systems configurationFilePath = configurationFilePath.replaceFirst("^~", System.getProperty("user.home")); // Configuration properties file is optional final File configurationFile = new File(configurationFilePath); if (!configurationFile.exists()) { log.error("Configuration file '{}' not found.", configurationFilePath); return properties; } try { final FileReader fileReader = new FileReader(configurationFile); properties.load(fileReader); } catch (final FileNotFoundException fnf) { log.error("Configuration file '{}' not found.", configurationFilePath); } catch (final IOException ioe) { log.error( "Configuration file '{}' cannot be accessed or correctly parsed.", configurationFilePath); } return properties; } /** Returns the detected hostname. First tries locally, then using DNS */ private String getHostName() { String possibleHostname = null; // Try environment variable. This works in almost all environments if (System.getProperty("os.name").startsWith("Windows")) { possibleHostname = System.getenv("COMPUTERNAME"); } else { possibleHostname = System.getenv("HOSTNAME"); } if (possibleHostname != null && !possibleHostname.isEmpty()) { log.debug("Determined hostname from environment variable"); return possibleHostname.trim(); } // Try hostname command try { final Process process = Runtime.getRuntime().exec("hostname"); final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); possibleHostname = reader.readLine(); } catch (final Exception e) { // Ignore. Hostname command is not always available } if (possibleHostname != null && !possibleHostname.isEmpty()) { log.debug("Determined hostname from hostname command"); return possibleHostname.trim(); } // From DNS try { return InetAddress.getLocalHost().getHostName(); } catch (final UnknownHostException e) { // If we are not able to detect the hostname we do not throw an exception. } return null; } // This has to be placed after all other static fields to give them a chance to initialize private static final Config INSTANCE = new Config(); public static Config get() { return INSTANCE; } public static Config get(final Properties properties) { if (properties == null || properties.isEmpty()) { return INSTANCE; } else { return new Config(properties, INSTANCE); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy