Skip to content

Commit

Permalink
chore(serverless): lazy load slow package imports (#8994)
Browse files Browse the repository at this point in the history
Lazy loads
+ `logging.handlers`
+ `multiprocessing`
+ `email.mime.application`
+ `email.mime.multipart`

All of which are slow to import and not needed when run in aws lambda.
This improves cold start time.

Also, updates tests to ensure the code is not accidentally updated in
the future to import these packages.

## Checklist

- [x] Change(s) are motivated and described in the PR description
- [x] Testing strategy is described if automated tests are not included
in the PR
- [x] Risks are described (performance impact, potential for breakage,
maintainability)
- [x] Change is maintainable (easy to change, telemetry, documentation)
- [x] [Library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
are followed or label `changelog/no-changelog` is set
- [x] Documentation is included (in-code, generated user docs, [public
corp docs](https://github.com/DataDog/documentation/))
- [x] Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))
- [x] If this PR changes the public interface, I've notified
`@DataDog/apm-tees`.

## Reviewer Checklist

- [x] Title is accurate
- [x] All changes are related to the pull request's stated goal
- [x]  Description motivates each change
- [x] Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- [x] Testing strategy adequately addresses listed risks
- [x] Change is maintainable (easy to change, telemetry, documentation)
- [x] Release note makes sense to a user of the library
- [x] Author has acknowledged and discussed the performance implications
of this PR as reported in the benchmarks PR comment
- [x] Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)

---------

Co-authored-by: Federico Mon <[email protected]>
  • Loading branch information
purple4reina and gnufede authored Apr 24, 2024
1 parent 5577a44 commit 5478ea5
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 7 deletions.
5 changes: 3 additions & 2 deletions ddtrace/_logger.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import logging
from logging.handlers import RotatingFileHandler
import os
from typing import Optional

Expand Down Expand Up @@ -71,11 +70,13 @@ def _add_file_handler(
log_level: int,
handler_name: Optional[str] = None,
max_file_bytes: int = DEFAULT_FILE_SIZE_BYTES,
) -> Optional[RotatingFileHandler]:
):
ddtrace_file_handler = None
if log_path is not None:
log_path = os.path.abspath(log_path)
num_backup = 1
from logging.handlers import RotatingFileHandler

ddtrace_file_handler = RotatingFileHandler(
filename=log_path, mode="a", maxBytes=max_file_bytes, backupCount=num_backup
)
Expand Down
3 changes: 2 additions & 1 deletion ddtrace/internal/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from inspect import iscoroutinefunction
from inspect import isgeneratorfunction
import ipaddress
import multiprocessing
import os
import platform
import re
Expand Down Expand Up @@ -477,4 +476,6 @@ def is_relative_to(self, other):


def get_mp_context():
import multiprocessing

return multiprocessing.get_context("fork" if sys.platform != "win32" else "spawn")
5 changes: 3 additions & 2 deletions ddtrace/internal/utils/http.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from contextlib import contextmanager
from dataclasses import dataclass
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from json import loads
import logging
import os
Expand Down Expand Up @@ -437,6 +435,9 @@ class FormData:


def multipart(parts: List[FormData]) -> Tuple[bytes, dict]:
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart

msg = MIMEMultipart("form-data")
del msg["MIME-Version"]

Expand Down
11 changes: 9 additions & 2 deletions tests/internal/test_serverless.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,15 @@ def test_slow_imports(monkeypatch):
# any of those modules are imported during the import of ddtrace.

blocklist = [
"ddtrace.appsec._api_security.api_manager",
"ddtrace.appsec._iast._ast.ast_patching",
"ddtrace.internal.telemetry.telemetry_writer",
"ddtrace.appsec._api_security.api_manager",
"email.mime.application",
"email.mime.multipart",
"logging.handlers",
"multiprocessing",
"importlib.metadata",
"importlib_metadata",
]
monkeypatch.setenv("DD_INSTRUMENTATION_TELEMETRY_ENABLED", False)
monkeypatch.setenv("DD_API_SECURITY_ENABLED", False)
Expand All @@ -117,12 +123,13 @@ def find_spec(self, fullname, *args):
deleted_modules = {}

for mod in sys.modules.copy():
if mod.startswith("ddtrace"):
if mod.startswith("ddtrace") or mod in blocklist:
deleted_modules[mod] = sys.modules[mod]
del sys.modules[mod]

with mock.patch("sys.meta_path", meta_path):
import ddtrace
import ddtrace.contrib.aws_lambda # noqa:F401
import ddtrace.contrib.psycopg # noqa:F401

for name, mod in deleted_modules.items():
Expand Down

0 comments on commit 5478ea5

Please sign in to comment.