Repository: open-telemetry/opentelemetry-java
File: api/incubator/src/main/java/io/opentelemetry/api/incubator/propagation/EnvironmentGetter.java (Java)

Code before:
/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package io.opentelemetry.api.incubator.propagation;

import io.opentelemetry.context.propagation.TextMapGetter;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * A {@link TextMapGetter} that extracts context from a map carrier, intended for use with
 * environment variables.
 *
 * <p>Standard environment variable names are uppercase (e.g., {@code TRACEPARENT}, {@code
 * TRACESTATE}, {@code BAGGAGE}). This getter translates keys to uppercase before looking them up in
 * the carrier.
 */
public enum EnvironmentGetter implements TextMapGetter<Map<String, String>> {
  INSTANCE;

  @Override
  public Iterable<String> keys(Map<String, String> carrier) {
    if (carrier == null) {
      return Collections.emptyList();
    }
    return carrier.keySet();
  }

  @Nullable
  @Override
  public String get(@Nullable Map<String, String> carrier, String key) {
    if (carrier == null || key == null) {
      return null;
    }
    // Spec recommends using uppercase for environment variable names.
    return carrier.get(key.toUpperCase(Locale.ROOT));
  }

  @Override
  public String toString() {
    return "EnvironmentGetter";
  }
}

Review comment (suggestion):
We don't use this enum style of pattern for singletons in this repo. Instead, we prefer:

- A public final class
- A private constructor
- A private static final reference to the singleton instance
- A public static accessor `public static EnvironmentGetter getInstance()`, accessing the singleton instance

Code after:
/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package io.opentelemetry.api.incubator.propagation;

import io.opentelemetry.context.propagation.TextMapGetter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;

/**
 * A {@link TextMapGetter} that extracts context from a map carrier, intended for use with
 * environment variables in child processes.
 *
 * <p>This is useful when a child process needs to extract propagated context from its environment.
 * For example:
 *
 * <pre>{@code
 * Map<String, String> env = System.getenv();
 * Context context = contextPropagators.getTextMapPropagator()
 *     .extract(Context.current(), env, EnvironmentGetter.getInstance());
 * }</pre>
 *
 * <p>This getter automatically sanitizes keys to match environment variable naming conventions:
 *
 * <ul>
 *   <li>Converts keys to uppercase (e.g., {@code traceparent} becomes {@code TRACEPARENT})
 *   <li>Replaces {@code .} and {@code -} with underscores
 * </ul>
 *
 * <p>Values are validated to contain only characters valid in HTTP header fields per <a
 * href="https://datatracker.ietf.org/doc/html/rfc9110#section-5.5">RFC 9110</a> (visible ASCII
 * characters, space, and horizontal tab). Values containing invalid characters are treated as
 * absent and {@code null} is returned.
 *
 * @see <a href=
 *     "https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/context/env-carriers.md#format-restrictions">Environment
 *     Variable Format Restrictions</a>
 */
public final class EnvironmentGetter implements TextMapGetter<Map<String, String>> {