Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 16 additions & 33 deletions sentry_sdk/integrations/gcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
from typing import TYPE_CHECKING

import sentry_sdk
from sentry_sdk.api import continue_trace
from sentry_sdk.consts import OP
from sentry_sdk.data_collection import _apply_data_collection_filtering_to_query_string
from sentry_sdk.integrations import Integration
from sentry_sdk.integrations._wsgi_common import _filter_headers
from sentry_sdk.integrations.cloud_resource_context import CLOUD_PROVIDER
from sentry_sdk.scope import Scope, should_send_default_pii
from sentry_sdk.traces import SegmentNameSource
from sentry_sdk.tracing import TransactionSource
from sentry_sdk.tracing_utils import has_span_streaming_enabled
from sentry_sdk.utils import (
AnnotatedValue,
TimeoutThread,
Expand Down Expand Up @@ -140,36 +137,22 @@ def sentry_func(
if environ.get("ENTRY_POINT"):
additional_attributes["faas.entry_point"] = environ.get("ENTRY_POINT")

if has_span_streaming_enabled(client.options):
sentry_sdk.traces.continue_trace(headers)
Scope.set_custom_sampling_context(sampling_context)
span_ctx = sentry_sdk.traces.start_span(
name=function_name,
parent_span=None,
attributes={
"sentry.op": OP.FUNCTION_GCP,
"sentry.origin": GcpIntegration.origin,
"sentry.segment.name.source": SegmentNameSource.COMPONENT,
"cloud.provider": CLOUD_PROVIDER.GCP,
"faas.name": function_name,
**header_attributes,
**additional_attributes,
},
)
else:
transaction = continue_trace(
headers,
op=OP.FUNCTION_GCP,
name=environ.get("FUNCTION_NAME", ""),
source=TransactionSource.COMPONENT,
origin=GcpIntegration.origin,
)

span_ctx = sentry_sdk.start_transaction(
transaction, custom_sampling_context=sampling_context
)

with span_ctx:
sentry_sdk.traces.continue_trace(headers)
Scope.set_custom_sampling_context(sampling_context)

with sentry_sdk.traces.start_span(
name=function_name,
parent_span=None,
attributes={
"sentry.op": OP.FUNCTION_GCP,
"sentry.origin": GcpIntegration.origin,
"sentry.segment.name.source": SegmentNameSource.COMPONENT,
"cloud.provider": CLOUD_PROVIDER.GCP,
"faas.name": function_name,
**header_attributes,
**additional_attributes,
},
):
try:
return func(functionhandler, gcp_event, *args, **kwargs)
except Exception:
Expand Down
194 changes: 18 additions & 176 deletions tests/integrations/gcp/test_gcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,65 +238,6 @@ def cloud_function(functionhandler, event):
assert envelope_items[0]["tags"]["cloud_function"] == "true"


def test_performance_no_error(run_cloud_function):
envelope_items, _, _ = run_cloud_function(
dedent(
"""
functionhandler = None
event = {}
def cloud_function(functionhandler, event):
return "test_string"
"""
)
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(traces_sample_rate=1.0)
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
)
)

assert envelope_items[0]["type"] == "transaction"
assert envelope_items[0]["contexts"]["trace"]["op"] == "function.gcp"
assert envelope_items[0]["transaction"].startswith("Google Cloud function")
assert envelope_items[0]["transaction_info"] == {"source": "component"}
assert envelope_items[0]["transaction"] in envelope_items[0]["request"]["url"]


def test_performance_error(run_cloud_function):
envelope_items, _, _ = run_cloud_function(
dedent(
"""
functionhandler = None
event = {}
def cloud_function(functionhandler, event):
raise Exception("something went wrong")
"""
)
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(traces_sample_rate=1.0)
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
)
)

assert envelope_items[0]["level"] == "error"
(exception,) = envelope_items[0]["exception"]["values"]

assert exception["type"] == "Exception"
assert exception["value"] == "something went wrong"
assert exception["mechanism"]["type"] == "gcp"
assert not exception["mechanism"]["handled"]

assert envelope_items[1]["type"] == "transaction"
assert envelope_items[1]["contexts"]["trace"]["op"] == "function.gcp"
assert envelope_items[1]["transaction"].startswith("Google Cloud function")
assert envelope_items[1]["transaction"] in envelope_items[0]["request"]["url"]


def test_traces_sampler_gets_correct_values_in_sampling_context(
run_cloud_function,
DictionaryContaining, # noqa:N803
Expand Down Expand Up @@ -367,6 +308,7 @@ def _safe_is_equal(x, y):

init_sdk(
traces_sampler=traces_sampler,
trace_lifecycle="stream",
)

gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
Expand All @@ -379,9 +321,9 @@ def _safe_is_equal(x, y):

def test_error_has_new_trace_context_performance_enabled(run_cloud_function):
"""
Check if an 'trace' context is added to errros and transactions when performance monitoring is enabled.
Check if a 'trace' context is added to errors and spans when performance monitoring is enabled.
"""
envelope_items, _, _ = run_cloud_function(
envelope_items, _, span_items = run_cloud_function(
dedent(
"""
functionhandler = None
Expand All @@ -395,26 +337,26 @@ def cloud_function(functionhandler, event):
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(traces_sample_rate=1.0)
init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream")
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
)
)
(msg_event, error_event, transaction_event) = envelope_items
(msg_event, error_event) = envelope_items

assert "trace" in msg_event["contexts"]
assert "trace_id" in msg_event["contexts"]["trace"]

assert "trace" in error_event["contexts"]
assert "trace_id" in error_event["contexts"]["trace"]

assert "trace" in transaction_event["contexts"]
assert "trace_id" in transaction_event["contexts"]["trace"]
assert len(span_items) == 1
segment_span = span_items[0]

assert (
msg_event["contexts"]["trace"]["trace_id"]
== error_event["contexts"]["trace"]["trace_id"]
== transaction_event["contexts"]["trace"]["trace_id"]
== segment_span["trace_id"]
)


Expand Down Expand Up @@ -456,59 +398,6 @@ def cloud_function(functionhandler, event):
)


def test_error_has_existing_trace_context_performance_enabled(run_cloud_function):
"""
Check if an 'trace' context is added to errros and transactions
from the incoming 'sentry-trace' header when performance monitoring is enabled.
"""
trace_id = "471a43a4192642f0b136d5159a501701"
parent_span_id = "6e8f22c393e68f19"
parent_sampled = 1
sentry_trace_header = "{}-{}-{}".format(trace_id, parent_span_id, parent_sampled)

envelope_items, _, _ = run_cloud_function(
dedent(
"""
functionhandler = None

from collections import namedtuple
GCPEvent = namedtuple("GCPEvent", ["headers"])
event = GCPEvent(headers={"sentry-trace": "%s"})

def cloud_function(functionhandler, event):
sentry_sdk.capture_message("hi")
x = 3/0
return "3"
"""
% sentry_trace_header
)
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(traces_sample_rate=1.0)
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
)
)
(msg_event, error_event, transaction_event) = envelope_items

assert "trace" in msg_event["contexts"]
assert "trace_id" in msg_event["contexts"]["trace"]

assert "trace" in error_event["contexts"]
assert "trace_id" in error_event["contexts"]["trace"]

assert "trace" in transaction_event["contexts"]
assert "trace_id" in transaction_event["contexts"]["trace"]

assert (
msg_event["contexts"]["trace"]["trace_id"]
== error_event["contexts"]["trace"]["trace_id"]
== transaction_event["contexts"]["trace"]["trace_id"]
== "471a43a4192642f0b136d5159a501701"
)


def test_error_has_existing_trace_context_performance_disabled(run_cloud_function):
"""
Check if an 'trace' context is added to errros and transactions
Expand Down Expand Up @@ -559,7 +448,7 @@ def cloud_function(functionhandler, event):


def test_span_origin(run_cloud_function):
events, _, _ = run_cloud_function(
_, _, span_items = run_cloud_function(
dedent(
"""
functionhandler = None
Expand All @@ -571,18 +460,17 @@ def cloud_function(functionhandler, event):
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(traces_sample_rate=1.0)
init_sdk(traces_sample_rate=1.0, trace_lifecycle="stream")
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
)
)

(event,) = events

assert event["contexts"]["trace"]["origin"] == "auto.function.gcp"
assert len(span_items) == 1
assert span_items[0]["attributes"]["sentry.origin"] == "auto.function.gcp"


def test_span_streaming_no_error(run_cloud_function):
def test_performance_no_error(run_cloud_function):
_, _, span_items = run_cloud_function(
dedent(
"""
Expand Down Expand Up @@ -616,7 +504,7 @@ def cloud_function(functionhandler, event):
assert segment_span["attributes"]["faas.entry_point"] == "cloud_function"


def test_span_streaming_error(run_cloud_function):
def test_performance_error(run_cloud_function):
envelope_items, _, span_items = run_cloud_function(
dedent(
"""
Expand Down Expand Up @@ -657,7 +545,7 @@ def cloud_function(functionhandler, event):
assert segment_span["status"] == SpanStatus.ERROR


def test_span_streaming_existing_trace_context(run_cloud_function):
def test_existing_trace_context(run_cloud_function):
trace_id = "471a43a4192642f0b136d5159a501701"
parent_span_id = "6e8f22c393e68f19"
parent_sampled = 1
Expand Down Expand Up @@ -705,7 +593,7 @@ def cloud_function(functionhandler, event):
assert segment_span["attributes"]["faas.entry_point"] == "cloud_function"


def test_span_streaming_request_attributes(run_cloud_function):
def test_request_attributes(run_cloud_function):
_, _, span_items = run_cloud_function(
dedent(
"""
Expand Down Expand Up @@ -746,7 +634,7 @@ def cloud_function(functionhandler, event):
assert attrs["faas.entry_point"] == "cloud_function"


def test_span_streaming_no_query_string_without_pii(run_cloud_function):
def test_no_query_string_without_pii(run_cloud_function):
_, _, span_items = run_cloud_function(
dedent(
"""
Expand Down Expand Up @@ -863,53 +751,7 @@ def _build_init_kwargs(send_default_pii, data_collection):
"send_default_pii, data_collection, expected_event, expected_span",
_QUERY_STRING_DATA_COLLECTION_CASES,
)
def test_query_string_data_collection_event_processor(
run_cloud_function,
send_default_pii,
data_collection,
expected_event,
expected_span,
):
init_kwargs = _build_init_kwargs(send_default_pii, data_collection)
envelope_items, _, _ = run_cloud_function(
dedent(
"""
functionhandler = None

from collections import namedtuple
GCPEvent = namedtuple("GCPEvent", ["headers", "method", "query_string"])
event = GCPEvent(
headers={},
method="GET",
query_string=b"toy=tennisball&color=red&auth=secret",
)

def cloud_function(functionhandler, event):
raise Exception("something went wrong")
"""
)
+ FUNCTIONS_PRELUDE
+ dedent(
"""
init_sdk(%s)
gcp_functions.worker_v1.FunctionHandler.invoke_user_function(functionhandler, event)
"""
% init_kwargs
)
)

request = envelope_items[0]["request"]
if expected_event is None:
assert "query_string" not in request
else:
assert request["query_string"] == expected_event


@pytest.mark.parametrize(
"send_default_pii, data_collection, expected_event, expected_span",
_QUERY_STRING_DATA_COLLECTION_CASES,
)
def test_query_string_data_collection_span_streaming(
def test_query_string_data_collection(
run_cloud_function,
send_default_pii,
data_collection,
Expand Down
Loading