Config.java 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright The OpenTelemetry Authors
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. package io.opentelemetry.instrumentation.api.config;
  6. import static java.util.Objects.requireNonNull;
  7. import static java.util.logging.Level.FINE;
  8. import com.google.auto.value.AutoValue;
  9. import java.time.Duration;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.logging.Logger;
  13. import javax.annotation.Nullable;
  14. /**
  15. * Represents the global instrumentation configuration consisting of system properties and
  16. * environment variables; and, if using the OpenTelemetry javaagent, contents of the agent
  17. * configuration file and properties defined by the {@code ContextCustomizer} SPI implementations.
  18. *
  19. * <p>In case any {@code get*()} method variant gets called for the same property more than once
  20. * (e.g. each time an advice class executes) it is suggested to cache the result instead of
  21. * repeatedly calling {@link Config}. The instrumentation configuration does not change during the
  22. * runtime so retrieving the property once and storing its result in a static final field allows JIT
  23. * to do its magic and remove some code branches.
  24. *
  25. * @deprecated This class is deprecated and will be removed from instrumentation-api in the next
  26. * release. Please use programmatic configuration (e.g. builder methods) instead.
  27. */
  28. @Deprecated
  29. @AutoValue
  30. @AutoValue.CopyAnnotations
  31. public abstract class Config {
  32. private static final Logger logger = Logger.getLogger(Config.class.getName());
  33. // lazy initialized, so that javaagent can set it, and library instrumentation can fall back and
  34. // read system properties
  35. @Nullable private static volatile Config instance = null;
  36. /** Start building a new {@link Config} instance. */
  37. public static ConfigBuilder builder() {
  38. return new ConfigBuilder();
  39. }
  40. static Config create(Map<String, String> allProperties) {
  41. return new AutoValue_Config(allProperties);
  42. }
  43. // package protected constructor to make extending this class impossible
  44. Config() {}
  45. /**
  46. * Sets the instrumentation configuration singleton. This method is only supposed to be called
  47. * once, during the javaagent initialization, just before {@link Config#get()} is used for the
  48. * first time.
  49. *
  50. * <p>This method is internal and is hence not for public use. Its API is unstable and can change
  51. * at any time.
  52. */
  53. public static void internalInitializeConfig(Config config) {
  54. if (instance != null) {
  55. logger.warning("Config#INSTANCE was already set earlier");
  56. return;
  57. }
  58. instance = requireNonNull(config);
  59. }
  60. /** Returns the global instrumentation configuration. */
  61. public static Config get() {
  62. if (instance == null) {
  63. // this should only happen in library instrumentation
  64. //
  65. // no need to synchronize because worst case is creating instance more than once
  66. instance = builder().addEnvironmentVariables().addSystemProperties().build();
  67. }
  68. return instance;
  69. }
  70. /**
  71. * Returns all properties stored in this {@link Config} instance. The returned map is
  72. * unmodifiable.
  73. */
  74. public abstract Map<String, String> getAllProperties();
  75. /**
  76. * Returns a string-valued configuration property or {@code null} if a property with name {@code
  77. * name} has not been configured.
  78. */
  79. @Nullable
  80. public String getString(String name) {
  81. return getRawProperty(name, null);
  82. }
  83. /**
  84. * Returns a string-valued configuration property or {@code defaultValue} if a property with name
  85. * {@code name} has not been configured.
  86. */
  87. public String getString(String name, String defaultValue) {
  88. return getRawProperty(name, defaultValue);
  89. }
  90. /**
  91. * Returns a boolean-valued configuration property or {@code defaultValue} if a property with name
  92. * {@code name} has not been configured.
  93. */
  94. public boolean getBoolean(String name, boolean defaultValue) {
  95. return safeGetTypedProperty(name, ConfigValueParsers::parseBoolean, defaultValue);
  96. }
  97. /**
  98. * Returns an integer-valued configuration property or {@code defaultValue} if a property with
  99. * name {@code name} has not been configured or when parsing has failed.
  100. */
  101. public int getInt(String name, int defaultValue) {
  102. return safeGetTypedProperty(name, ConfigValueParsers::parseInt, defaultValue);
  103. }
  104. /**
  105. * Returns a long-valued configuration property or {@code defaultValue} if a property with name
  106. * {@code name} has not been configured or when parsing has failed.
  107. */
  108. public long getLong(String name, long defaultValue) {
  109. return safeGetTypedProperty(name, ConfigValueParsers::parseLong, defaultValue);
  110. }
  111. /**
  112. * Returns a double-valued configuration property or {@code defaultValue} if a property with name
  113. * {@code name} has not been configured or when parsing has failed.
  114. */
  115. public double getDouble(String name, double defaultValue) {
  116. return safeGetTypedProperty(name, ConfigValueParsers::parseDouble, defaultValue);
  117. }
  118. /**
  119. * Returns a duration-valued configuration property or {@code defaultValue} if a property with
  120. * name {@code name} has not been configured or when parsing has failed.
  121. *
  122. * <p>Durations can be of the form "{number}{unit}", where unit is one of:
  123. *
  124. * <ul>
  125. * <li>ms
  126. * <li>s
  127. * <li>m
  128. * <li>h
  129. * <li>d
  130. * </ul>
  131. *
  132. * <p>If no unit is specified, milliseconds is the assumed duration unit.
  133. *
  134. * <p>Examples: 10s, 20ms, 5000
  135. */
  136. public Duration getDuration(String name, Duration defaultValue) {
  137. return safeGetTypedProperty(name, ConfigValueParsers::parseDuration, defaultValue);
  138. }
  139. /**
  140. * Returns a list-valued configuration property or {@code defaultValue} if a property with name
  141. * {@code name} has not been configured. The format of the original value must be comma-separated,
  142. * e.g. {@code one,two,three}. The returned list is unmodifiable.
  143. */
  144. public List<String> getList(String name, List<String> defaultValue) {
  145. return safeGetTypedProperty(name, ConfigValueParsers::parseList, defaultValue);
  146. }
  147. /**
  148. * Returns a map-valued configuration property or {@code defaultValue} if a property with name
  149. * {@code name} has not been configured or when parsing has failed. The format of the original
  150. * value must be comma-separated for each key, with an '=' separating the key and value, e.g.
  151. * {@code key=value,anotherKey=anotherValue}. The returned map is unmodifiable.
  152. */
  153. public Map<String, String> getMap(String name, Map<String, String> defaultValue) {
  154. return safeGetTypedProperty(name, ConfigValueParsers::parseMap, defaultValue);
  155. }
  156. private <T> T safeGetTypedProperty(String name, ConfigValueParser<T> parser, T defaultValue) {
  157. try {
  158. T value = getTypedProperty(name, parser);
  159. return value == null ? defaultValue : value;
  160. } catch (RuntimeException t) {
  161. if (logger.isLoggable(FINE)) {
  162. logger.log(FINE, "Error occurred during parsing: " + t.getMessage(), t);
  163. }
  164. return defaultValue;
  165. }
  166. }
  167. @Nullable
  168. private <T> T getTypedProperty(String name, ConfigValueParser<T> parser) {
  169. String value = getRawProperty(name, null);
  170. if (value == null || value.trim().isEmpty()) {
  171. return null;
  172. }
  173. return parser.parse(name, value);
  174. }
  175. private String getRawProperty(String name, String defaultValue) {
  176. return getAllProperties().getOrDefault(NamingConvention.DOT.normalize(name), defaultValue);
  177. }
  178. /**
  179. * Returns a new {@link ConfigBuilder} instance populated with the properties of this {@link
  180. * Config}.
  181. */
  182. public ConfigBuilder toBuilder() {
  183. return new ConfigBuilder(getAllProperties());
  184. }
  185. }