diff --git a/solarwinds_apm/k8s.py b/solarwinds_apm/k8s.py index 499b99bb6..6595cce75 100644 --- a/solarwinds_apm/k8s.py +++ b/solarwinds_apm/k8s.py @@ -30,6 +30,12 @@ def _pod_name() -> str: + """ + Get Kubernetes pod name from environment or system hostname. + + Returns: + str: The pod name. + """ env = os.getenv(NAME_ENV) if env: logger.debug("read pod name from env") @@ -39,6 +45,15 @@ def _pod_name() -> str: def _pod_uid(mount_info: str) -> str | None: + """ + Get Kubernetes pod UID from environment or mountinfo file. + + Parameters: + mount_info (str): Path to mountinfo file. + + Returns: + str | None: The pod UID if found, None otherwise. + """ env = os.getenv(UID_ENV) if env: logger.debug("read pod uid from env") @@ -70,6 +85,15 @@ def _pod_uid(mount_info: str) -> str | None: def _pod_namespace(namespace: str) -> str | None: + """ + Get Kubernetes namespace from environment or namespace file. + + Parameters: + namespace (str): Path to namespace file. + + Returns: + str | None: The namespace if found, None otherwise. + """ env = os.getenv(NAMESPACE_ENV) if env: logger.debug("read pod namespace from env") @@ -84,18 +108,29 @@ def _pod_namespace(namespace: str) -> str | None: class K8sResourceDetector(ResourceDetector): - """Detects attribute values only available when the app is running on k8s - and returns them in a Resource. - """ + """Detect Kubernetes resource attributes when running in a Kubernetes environment.""" def __init__( self, namespace: str = NAMESPACE_FILE, mountinfo: str = MOUNTINFO_FILE - ): + ) -> None: + """ + Initialize K8s Resource Detector. + + Parameters: + namespace (str): Path to namespace file. Defaults to NAMESPACE_FILE. + mountinfo (str): Path to mountinfo file. Defaults to MOUNTINFO_FILE. + """ super().__init__() self._namespace = namespace self._mountinfo = mountinfo def detect(self) -> Resource: + """ + Detect Kubernetes resource attributes. + + Returns: + Resource: Resource with K8s namespace, pod UID, and pod name attributes if available. + """ attributes = {} namespace = _pod_namespace(self._namespace) diff --git a/solarwinds_apm/tracer_provider.py b/solarwinds_apm/tracer_provider.py index de0a36816..3e4f74e1c 100644 --- a/solarwinds_apm/tracer_provider.py +++ b/solarwinds_apm/tracer_provider.py @@ -4,6 +4,8 @@ # # Unless required by applicable law or agreed to in writing, software distributed under the License 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. +"""SolarWinds TracerProvider with custom shutdown behavior.""" + from opentelemetry.sdk.trace import TracerProvider from typing_extensions import override @@ -11,8 +13,18 @@ class SolarwindsTracerProvider(TracerProvider): + """Provide custom TracerProvider with HttpSampler shutdown support. + + Extends OpenTelemetry TracerProvider to properly shutdown HttpSampler. + """ + @override def shutdown(self) -> None: + """ + Shutdown the tracer provider and its sampler. + + Ensures HttpSampler daemon thread is properly terminated before parent shutdown. + """ if isinstance(self.sampler, HttpSampler): self.sampler.shutdown() super().shutdown() diff --git a/solarwinds_apm/uams.py b/solarwinds_apm/uams.py index b498028d9..fce3994b2 100644 --- a/solarwinds_apm/uams.py +++ b/solarwinds_apm/uams.py @@ -32,6 +32,15 @@ def _read_from_file(uams_file: str) -> dict: + """ + Read UAMS client ID from file. + + Parameters: + uams_file (str): Path to UAMS client ID file. + + Returns: + dict: Dictionary with UAMS client ID and host ID attributes, or empty dict on error. + """ try: with open(uams_file, encoding="utf-8") as file: uams_id = file.read().strip() @@ -46,6 +55,12 @@ def _read_from_file(uams_file: str) -> dict: def _read_from_api() -> dict: + """ + Read UAMS client ID from local API endpoint. + + Returns: + dict: Dictionary with UAMS client ID and host ID attributes, or empty dict on error. + """ try: token = attach(set_value(_SUPPRESS_INSTRUMENTATION_KEY, True)) response = requests.get(UAMS_CLIENT_URL, timeout=1) @@ -68,14 +83,24 @@ def _read_from_api() -> dict: class UamsResourceDetector(ResourceDetector): - """Detects attribute values only available when the app is running on k8s - and returns them in a Resource. - """ + """Detect UAMS client attributes for SolarWinds APM resource identification.""" - def __init__(self, uams=UAMS_CLIENT_PATH): + def __init__(self, uams: str = UAMS_CLIENT_PATH) -> None: + """ + Initialize UAMS Resource Detector. + + Parameters: + uams (str): Path to UAMS client ID file. Defaults to UAMS_CLIENT_PATH. + """ super().__init__() self._uams = uams - def detect(self) -> "Resource": + def detect(self) -> Resource: + """ + Detect UAMS resource attributes. + + Returns: + Resource: Resource with UAMS client ID and host ID attributes if available. + """ attributes = _read_from_file(self._uams) or _read_from_api() or {} return Resource(attributes) diff --git a/solarwinds_apm/version.py b/solarwinds_apm/version.py index 6c235c596..0047ca21c 100644 --- a/solarwinds_apm/version.py +++ b/solarwinds_apm/version.py @@ -1 +1,3 @@ +"""SolarWinds APM version information.""" + __version__ = "5.2.0"