Skip to content

Commit

Permalink
Properly parent lazily loaded module imports. (#446)
Browse files Browse the repository at this point in the history
* Properly parent lazily loaded module imports.

* Test parenting for lazy loaded package.

* Clear lists instead of updating the reference.
  • Loading branch information
purple4reina committed Mar 14, 2024
1 parent 6bccf3b commit 1015d8d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 7 deletions.
15 changes: 10 additions & 5 deletions datadog_lambda/cold_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
_cold_start = True
_proactive_initialization = False
_lambda_container_initialized = False
_tracer = None


def set_cold_start(init_timestamp_ns):
Expand All @@ -18,6 +19,7 @@ def set_cold_start(init_timestamp_ns):
global _cold_start
global _lambda_container_initialized
global _proactive_initialization
global _tracer
if not _lambda_container_initialized:
now = time.time_ns()
if (now - init_timestamp_ns) // 1_000_000_000 > 10:
Expand All @@ -29,6 +31,7 @@ def set_cold_start(init_timestamp_ns):
_cold_start = False
_proactive_initialization = False
_lambda_container_initialized = True
from ddtrace import tracer as _tracer


def is_cold_start():
Expand Down Expand Up @@ -62,6 +65,9 @@ def __init__(self, module_name, full_file_path, start_time_ns, end_time_ns=None)
self.start_time_ns = start_time_ns
self.end_time_ns = end_time_ns
self.children = []
self.context = None
if _lambda_container_initialized:
self.context = _tracer.context_provider.active()


root_nodes: List[ImportNode] = []
Expand All @@ -70,10 +76,8 @@ def __init__(self, module_name, full_file_path, start_time_ns, end_time_ns=None)


def reset_node_stacks():
global root_nodes
root_nodes = []
global import_stack
import_stack = []
root_nodes.clear()
import_stack.clear()


def push_node(module_name, file_path):
Expand Down Expand Up @@ -183,7 +187,8 @@ def trace(self, root_nodes: List[ImportNode] = root_nodes):
cold_start_span = self.create_cold_start_span(cold_start_span_start_time_ns)
while root_nodes:
root_node = root_nodes.pop()
self.trace_tree(root_node, cold_start_span)
parent = root_node.context or cold_start_span
self.trace_tree(root_node, parent)
self.finish_span(cold_start_span, cold_start_span_end_time_ns)

def trace_tree(self, import_node: ImportNode, parent_span):
Expand Down
46 changes: 44 additions & 2 deletions tests/test_cold_start.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import os
import time
import unittest
import datadog_lambda.cold_start as cold_start

from sys import modules, meta_path
import os
from unittest.mock import MagicMock

import datadog_lambda.cold_start as cold_start
import datadog_lambda.wrapper as wrapper


class TestColdStartTracingSetup(unittest.TestCase):
def test_proactive_init(self):
Expand Down Expand Up @@ -234,3 +237,42 @@ def test_trace_ignore_libs(self):
self.cold_start_tracer.trace(nodes)
self.mock_activate.assert_called_once_with(self.mock_trace_ctx)
self.assertEqual(self.output_spans, ["node_0", "unittest_cold_start"])


def test_lazy_loaded_package_imports(monkeypatch):

spans = []

def finish(span):
spans.append(span)

monkeypatch.setattr(wrapper.tracer, "_on_span_finish", finish)
monkeypatch.setattr(wrapper, "is_new_sandbox", lambda: True)
monkeypatch.setattr("datadog_lambda.wrapper.dd_tracing_enabled", True)
monkeypatch.setenv(
"DD_COLD_START_TRACE_SKIP_LIB", "ddtrace.contrib.logging,datadog_lambda.wrapper"
)
monkeypatch.setenv("DD_MIN_COLD_START_DURATION", "0")

@wrapper.datadog_lambda_wrapper
def handler(event, context):
import tabnanny

lambda_context = MagicMock()
lambda_context.invoked_function_arn = (
"arn:aws:lambda:us-west-1:123457598159:function:python-layer-test:1"
)

handler.cold_start_tracing = True
handler({}, lambda_context)

function_span = import_span = None
for span in spans:
if span.resource == "tabnanny":
import_span = span
elif span.name == "aws.lambda":
function_span = span

assert function_span is not None
assert import_span is not None
assert import_span.parent_id == function_span.span_id

0 comments on commit 1015d8d

Please sign in to comment.