• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HowFast / apm-python / 06b7e795-a650-4df1-9f26-225db7666945

24 Dec 2024 12:58AM UTC coverage: 92.333%. Remained the same
06b7e795-a650-4df1-9f26-225db7666945

Pull #21

circleci

web-flow
Bump jinja2 from 3.1.4 to 3.1.5

Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #21: Bump jinja2 from 3.1.4 to 3.1.5

53 of 61 branches covered (86.89%)

Branch coverage included in aggregate %.

224 of 239 relevant lines covered (93.72%)

0.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.29
/howfast_apm/core.py
1
import os
1✔
2
import logging
1✔
3
from typing import Optional, List
1✔
4
from datetime import datetime
1✔
5
from queue import Full, Empty
1✔
6

7
from .config import HOWFAST_APM_RECORD_INTERACTIONS
1✔
8
from .queue import queue
1✔
9
from .runner import Runner
1✔
10
from .hook_requests import install_hooks, Interaction
1✔
11

12
logger = logging.getLogger('howfast_apm')
1✔
13

14

15
class CoreAPM:
1✔
16
    """
17
    Base class that provides the shared code for:
18
    * starting the background thread
19
    * pushing points to the queue
20
    * storing external interactions
21
    """
22

23
    app_id: Optional[str]
1✔
24

25
    runner: Optional[Runner]
1✔
26

27
    record_interactions: bool
1✔
28
    interactions: List[Interaction] = []
1✔
29

30
    def __init__(self, record_interactions=HOWFAST_APM_RECORD_INTERACTIONS):
1✔
31
        self.record_interactions = bool(record_interactions)
1✔
32
        logger.debug("Interactions will %s", 'be enabled' if self.record_interactions else 'NOT be enabled')
1✔
33
        self.interactions = []
1✔
34

35
    def setup(
1✔
36
            self,
37
            # The HowFast app ID to use
38
            app_id: str = None,
39
    ):
40
        if app_id:
1✔
41
            self.app_id = app_id
1✔
42
        else:
43
            self.app_id = os.environ.get('HOWFAST_APM_DSN')
1✔
44

45
        if self.app_id:
1✔
46
            logger.info(f"HowFast APM configured with DSN {self.app_id}")
1✔
47
            self.start_background_thread()
1✔
48
            if self.record_interactions:
1✔
49
                self.setup_hooks()
1✔
50
        else:
51
            logger.warning("HowFast APM initialized with no DSN, reporting will be disabled.")
1✔
52

53
    def start_background_thread(self):
1✔
54
        """ Start the thread that will consume points from the queue and send them to the API """
55
        self.runner = Runner(queue=queue, app_id=self.app_id)
×
56
        self.runner.start()
×
57
        # TODO: stop the thread at some point?
58

59
    def setup_hooks(self) -> None:
1✔
60
        """ Install hooks to register what is slow """
61
        install_hooks(self.record_interaction)
1✔
62

63
    def record_interaction(self, interaction: Interaction) -> None:
1✔
64
        """ Save the interaction """
65
        self.interactions.append(interaction)
1✔
66

67
    def reset_interactions(self):
1✔
68
        self.interactions = []
1✔
69

70
    def save_point(
1✔
71
            self,
72
            time_request_started: datetime,
73
            time_elapsed: float,  # seconds
74
            method: str,
75
            uri: str,
76
            response_status: str = None,  # HTTP response status (200 OK, etc)
77
            endpoint_name: str = None,  # function name handling the request
78
            url_rule: str = None,  # Route pattern matched for this endpoint (/pet/<int:id>)
79
            is_not_found: bool = None,  # If the request did not match any route
80
    ) -> None:
81
        """
82
        Save a request/response performance information.
83

84
        This method is called by subclasses with their framework-specific information. We then add
85
        the core-level collected performance data (interactions) and call self._save_point().
86
        """
87
        self._save_point(
1✔
88
            time_request_started=time_request_started,
89
            time_elapsed=time_elapsed,
90
            method=method,
91
            uri=uri,
92
            interactions=self.interactions,
93
            response_status=response_status,
94
            endpoint_name=endpoint_name,
95
            url_rule=url_rule,
96
            is_not_found=is_not_found,
97
        )
98
        # Reset the list of interactions, since it's specific to a request/point
99
        self.reset_interactions()
1✔
100

101
    @staticmethod
1✔
102
    def _save_point(**kwargs) -> None:
1✔
103
        """ Save a request/response performance information """
104

105
        interaction_list = []
1✔
106
        interactions = kwargs.get('interactions', [])
1✔
107
        while interactions:
1✔
108
            interaction_list.append(interactions.pop().serialize())
1✔
109

110
        # Forward the arguments to the queue
111
        item = kwargs
1✔
112

113
        # Capped queue
114
        pushed = False
1✔
115
        while pushed is False:
1✔
116
            try:
1✔
117
                queue.put_nowait(item)
1✔
118
                pushed = True
1✔
119
            except Full:
1✔
120
                # The queue is full - let's pop the oldest element and discard it, and try again
121
                try:
1✔
122
                    queue.get_nowait()
1✔
123
                except Empty:
×
124
                    pass
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc