PHP 8.3.31
Preview: cloud_resource_context.py Size: 7.49 KB
/proc/self/root/opt/hc_python/lib/python3.12/site-packages/sentry_sdk/integrations/cloud_resource_context.py

import json
from typing import TYPE_CHECKING

import urllib3

from sentry_sdk.api import set_context
from sentry_sdk.integrations import Integration
from sentry_sdk.utils import logger

if TYPE_CHECKING:
    from typing import Dict


CONTEXT_TYPE = "cloud_resource"

HTTP_TIMEOUT = 2.0

AWS_METADATA_HOST = "169.254.169.254"
AWS_TOKEN_URL = "http://{}/latest/api/token".format(AWS_METADATA_HOST)
AWS_METADATA_URL = "http://{}/latest/dynamic/instance-identity/document".format(
    AWS_METADATA_HOST
)

GCP_METADATA_HOST = "metadata.google.internal"
GCP_METADATA_URL = "http://{}/computeMetadata/v1/?recursive=true".format(
    GCP_METADATA_HOST
)


class CLOUD_PROVIDER:  # noqa: N801
    """
    Name of the cloud provider.
    see https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud/
    """

    ALIBABA = "alibaba_cloud"
    AWS = "aws"
    AZURE = "azure"
    GCP = "gcp"
    IBM = "ibm_cloud"
    TENCENT = "tencent_cloud"


class CLOUD_PLATFORM:  # noqa: N801
    """
    The cloud platform.
    see https://opentelemetry.io/docs/reference/specification/resource/semantic_conventions/cloud/
    """

    AWS_EC2 = "aws_ec2"
    GCP_COMPUTE_ENGINE = "gcp_compute_engine"


class CloudResourceContextIntegration(Integration):
    """
    Adds cloud resource context to the Senty scope
    """

    identifier = "cloudresourcecontext"

    cloud_provider = ""

    aws_token = ""
    http = urllib3.PoolManager(timeout=HTTP_TIMEOUT)

    gcp_metadata = None

    def __init__(self, cloud_provider: str = "") -> None:
        CloudResourceContextIntegration.cloud_provider = cloud_provider

    @classmethod
    def _is_aws(cls) -> bool:
        try:
            r = cls.http.request(
                "PUT",
                AWS_TOKEN_URL,
                headers={"X-aws-ec2-metadata-token-ttl-seconds": "60"},
            )

            if r.status != 200:
                return False

            cls.aws_token = r.data.decode()
            return True

        except urllib3.exceptions.TimeoutError:
            logger.debug(
                "AWS metadata service timed out after %s seconds", HTTP_TIMEOUT
            )
            return False
        except Exception as e:
            logger.debug("Error checking AWS metadata service: %s", str(e))
            return False

    @classmethod
    def _get_aws_context(cls) -> "Dict[str, str]":
        ctx = {
            "cloud.provider": CLOUD_PROVIDER.AWS,
            "cloud.platform": CLOUD_PLATFORM.AWS_EC2,
        }

        try:
            r = cls.http.request(
                "GET",
                AWS_METADATA_URL,
                headers={"X-aws-ec2-metadata-token": cls.aws_token},
            )

            if r.status != 200:
                return ctx

            data = json.loads(r.data.decode("utf-8"))

            try:
                ctx["cloud.account.id"] = data["accountId"]
            except Exception:
                pass

            try:
                ctx["cloud.availability_zone"] = data["availabilityZone"]
            except Exception:
                pass

            try:
                ctx["cloud.region"] = data["region"]
            except Exception:
                pass

            try:
                ctx["host.id"] = data["instanceId"]
            except Exception:
                pass

            try:
                ctx["host.type"] = data["instanceType"]
            except Exception:
                pass

        except urllib3.exceptions.TimeoutError:
            logger.debug(
                "AWS metadata service timed out after %s seconds", HTTP_TIMEOUT
            )
        except Exception as e:
            logger.debug("Error fetching AWS metadata: %s", str(e))

        return ctx

    @classmethod
    def _is_gcp(cls) -> bool:
        try:
            r = cls.http.request(
                "GET",
                GCP_METADATA_URL,
                headers={"Metadata-Flavor": "Google"},
            )

            if r.status != 200:
                return False

            cls.gcp_metadata = json.loads(r.data.decode("utf-8"))
            return True

        except urllib3.exceptions.TimeoutError:
            logger.debug(
                "GCP metadata service timed out after %s seconds", HTTP_TIMEOUT
            )
            return False
        except Exception as e:
            logger.debug("Error checking GCP metadata service: %s", str(e))
            return False

    @classmethod
    def _get_gcp_context(cls) -> "Dict[str, str]":
        ctx = {
            "cloud.provider": CLOUD_PROVIDER.GCP,
            "cloud.platform": CLOUD_PLATFORM.GCP_COMPUTE_ENGINE,
        }

        gcp_metadata = cls.gcp_metadata
        try:
            if cls.gcp_metadata is None:
                r = cls.http.request(
                    "GET",
                    GCP_METADATA_URL,
                    headers={"Metadata-Flavor": "Google"},
                )

                if r.status != 200:
                    return ctx

                gcp_metadata = json.loads(r.data.decode("utf-8"))
                cls.gcp_metadata = gcp_metadata

            try:
                ctx["cloud.account.id"] = gcp_metadata["project"]["projectId"]
            except Exception:
                pass

            try:
                ctx["cloud.availability_zone"] = gcp_metadata["instance"]["zone"].split(
                    "/"
                )[-1]
            except Exception:
                pass

            try:
                # only populated in google cloud run
                ctx["cloud.region"] = gcp_metadata["instance"]["region"].split("/")[-1]
            except Exception:
                pass

            try:
                ctx["host.id"] = gcp_metadata["instance"]["id"]
            except Exception:
                pass

        except urllib3.exceptions.TimeoutError:
            logger.debug(
                "GCP metadata service timed out after %s seconds", HTTP_TIMEOUT
            )
        except Exception as e:
            logger.debug("Error fetching GCP metadata: %s", str(e))

        return ctx

    @classmethod
    def _get_cloud_provider(cls) -> str:
        if cls._is_aws():
            return CLOUD_PROVIDER.AWS

        if cls._is_gcp():
            return CLOUD_PROVIDER.GCP

        return ""

    @classmethod
    def _get_cloud_resource_context(cls) -> "Dict[str, str]":
        cloud_provider = (
            cls.cloud_provider
            if cls.cloud_provider != ""
            else CloudResourceContextIntegration._get_cloud_provider()
        )
        if cloud_provider in context_getters.keys():
            return context_getters[cloud_provider]()

        return {}

    @staticmethod
    def setup_once() -> None:
        cloud_provider = CloudResourceContextIntegration.cloud_provider
        unsupported_cloud_provider = (
            cloud_provider != "" and cloud_provider not in context_getters.keys()
        )

        if unsupported_cloud_provider:
            logger.warning(
                "Invalid value for cloud_provider: %s (must be in %s). Falling back to autodetection...",
                CloudResourceContextIntegration.cloud_provider,
                list(context_getters.keys()),
            )

        context = CloudResourceContextIntegration._get_cloud_resource_context()
        if context != {}:
            set_context(CONTEXT_TYPE, context)


# Map with the currently supported cloud providers
# mapping to functions extracting the context
context_getters = {
    CLOUD_PROVIDER.AWS: CloudResourceContextIntegration._get_aws_context,
    CLOUD_PROVIDER.GCP: CloudResourceContextIntegration._get_gcp_context,
}

Directory Contents

Dirs: 10 × Files: 73

Name Size Perms Modified Actions
celery DIR
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
django DIR
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
grpc DIR
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
redis DIR
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
spark DIR
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
- drwxr-xr-x 2026-06-11 06:30:31
Edit Download
19.28 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.09 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
39.00 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
876 B lrw-r--r-- 2026-06-11 06:30:30
Edit Download
5.70 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.23 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
20.06 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.28 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.68 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
1.51 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
17.41 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
4.91 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
6.20 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
7.21 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
4.51 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
5.85 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
7.49 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
10.44 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
1.86 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
8.02 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
2.25 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
1.93 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.04 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
5.28 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
8.27 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
10.57 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
2.72 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
4.93 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
5.71 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.79 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
9.80 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
8.19 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
15.28 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
48.31 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
18.13 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
1.87 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
13.03 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
11.46 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
15.69 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
6.35 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
23.12 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
787 B lrw-r--r-- 2026-06-11 06:30:30
Edit Download
53.38 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
1.08 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
7.99 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
4.41 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
8.21 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
7.42 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
6.82 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
7.32 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
5.75 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
7.81 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
9.44 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
15.25 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.58 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
5.02 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
5.24 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
27.93 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
11.04 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.19 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
14.01 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
17.39 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
2.35 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
6.88 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
10.79 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.67 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.72 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.02 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
1.65 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
15.03 KB lrw-r--r-- 2026-06-11 06:30:31
Edit Download
4.00 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
7.28 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download
12.51 KB lrw-r--r-- 2026-06-11 06:30:30
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).