Skip to content

Commit 94e43ec

Browse files
committed
Add objsize library for measuring bytes of spans
1 parent 835b2de commit 94e43ec

File tree

6 files changed

+677
-2
lines changed

6 files changed

+677
-2
lines changed

THIRD_PARTY_NOTICES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,11 @@ Distributed under the following license(s):
6262

6363
* [The BSD 2-Clause License](http://opensource.org/licenses/BSD-2-Clause)
6464

65+
## [objsize](https://pypi.org/project/objsize)
66+
67+
Copyright (c) 2006-2025, Liran Funaro
68+
All rights reserved.
69+
70+
Distributed under the following license(s):
71+
72+
* [The BSD 3-Clause "New" or "Revised" License](http://opensource.org/licenses/BSD-3-Clause)

newrelic/core/stats_engine.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -463,15 +463,15 @@ def add(*args, **kwargs):
463463

464464
@property
465465
def ft_samples(self):
466-
return (x[-1] if is_ft(x[-1]) for x in self.pq)
466+
return (x[-1] for x in self.pq if is_ft(x[-1]))
467467

468468
def is_ft(sample):
469469
# It's a FT span if it's an exit or entry span.
470470
return (len(sample) > 3 and sample[3]) or not sample[0].get("parentId")
471471

472472
def add(self, sample, priority=None):
473473
self.num_seen += 1
474-
if is_ft(sample:
474+
if is_ft(sample):
475475
self.ft_num_seen += 1
476476

477477
if priority is None:

newrelic/packages/objsize/LICENSE

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright (c) 2006-2025, Liran Funaro.
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
1. Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
2. Redistributions in binary form must reproduce the above copyright
9+
notice, this list of conditions and the following disclaimer in the
10+
documentation and/or other materials provided with the distribution.
11+
3. Neither the name of the copyright holder nor the
12+
names of its contributors may be used to endorse or promote products
13+
derived from this software without specific prior written permission.
14+
15+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25+
POSSIBILITY OF SUCH DAMAGE.

newrelic/packages/objsize/__init__.py

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
"""
2+
Traversal over Python's objects subtree and calculating the total size of the subtree (deep size).
3+
"""
4+
5+
import warnings
6+
from typing import Any, Iterable, Iterator, Optional
7+
8+
from objsize.traverse import (
9+
FilterFunc,
10+
GetReferentsFunc,
11+
MarkedSet,
12+
ObjSizeSettings,
13+
SharedObjectOrFunctionType,
14+
SharedObjectType,
15+
SizeFunc,
16+
TraversalContext,
17+
default_get_referents,
18+
default_object_filter,
19+
safe_is_instance,
20+
shared_object_filter,
21+
shared_object_or_function_filter,
22+
)
23+
24+
__version__ = "0.7.1"
25+
26+
default_settings = ObjSizeSettings()
27+
"""
28+
The default instance :py:class:`obj objsize settings <objsize.traverse.ObjSizeSettings>`.
29+
It can be updated to modify the default behaviour of objsize.
30+
"""
31+
32+
33+
def traverse_bfs(
34+
*objs,
35+
exclude: Optional[Iterable[Any]] = None,
36+
marked_set: Optional[MarkedSet] = None,
37+
exclude_set: Optional[MarkedSet] = None,
38+
get_referents_func: Optional[GetReferentsFunc] = None,
39+
filter_func: Optional[FilterFunc] = None,
40+
exclude_modules_globals: Optional[bool] = None,
41+
) -> Iterator[Any]:
42+
"""
43+
Traverse all the arguments' subtree.
44+
By default, this excludes shared objects, i.e., types, modules, functions, and lambdas.
45+
46+
Parameters
47+
----------
48+
objs : object(s)
49+
One or more object(s).
50+
exclude :
51+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
52+
marked_set :
53+
See :py:class:`~objsize.traverse.TraversalContext`.
54+
exclude_set :
55+
See :py:class:`~objsize.traverse.TraversalContext`.
56+
get_referents_func :
57+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
58+
filter_func :
59+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
60+
exclude_modules_globals :
61+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
62+
63+
Yields
64+
------
65+
object
66+
The traversed objects, one by one.
67+
"""
68+
settings = default_settings.replace(get_referents_func, filter_func, None, exclude, exclude_modules_globals)
69+
yield from settings.traverse_bfs(*objs, marked_set=marked_set, exclude_set=exclude_set)
70+
71+
72+
def traverse_exclusive_bfs(
73+
*objs,
74+
exclude: Optional[Iterable[Any]] = None,
75+
marked_set: Optional[MarkedSet] = None,
76+
exclude_set: Optional[MarkedSet] = None,
77+
get_referents_func: Optional[GetReferentsFunc] = None,
78+
filter_func: Optional[FilterFunc] = None,
79+
exclude_modules_globals: Optional[bool] = None,
80+
) -> Iterator[Any]:
81+
"""
82+
Traverse all the arguments' subtree, excluding non-exclusive objects.
83+
That is, objects that are referenced by objects that are not in this subtree.
84+
85+
Parameters
86+
----------
87+
objs : object(s)
88+
One or more object(s).
89+
exclude :
90+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
91+
marked_set :
92+
See :py:class:`~objsize.traverse.TraversalContext`.
93+
exclude_set :
94+
See :py:class:`~objsize.traverse.TraversalContext`.
95+
get_referents_func :
96+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
97+
filter_func :
98+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
99+
exclude_modules_globals :
100+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
101+
102+
Yields
103+
------
104+
object
105+
The traversed objects, one by one.
106+
107+
See Also
108+
--------
109+
traverse_bfs : to understand which objects are traversed.
110+
"""
111+
settings = default_settings.replace(get_referents_func, filter_func, None, exclude, exclude_modules_globals)
112+
yield from settings.traverse_exclusive_bfs(*objs, marked_set=marked_set, exclude_set=exclude_set)
113+
114+
115+
def get_deep_size( # pylint: disable=too-many-arguments
116+
*objs,
117+
exclude: Optional[Iterable[Any]] = None,
118+
marked_set: Optional[MarkedSet] = None,
119+
exclude_set: Optional[MarkedSet] = None,
120+
get_size_func: Optional[SizeFunc] = None,
121+
get_referents_func: Optional[GetReferentsFunc] = None,
122+
filter_func: Optional[FilterFunc] = None,
123+
exclude_modules_globals: Optional[bool] = None,
124+
) -> int:
125+
"""
126+
Calculates the deep size of all the arguments.
127+
128+
Parameters
129+
----------
130+
objs : object(s)
131+
One or more object(s).
132+
exclude :
133+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
134+
marked_set :
135+
See :py:class:`~objsize.traverse.TraversalContext`.
136+
exclude_set :
137+
See :py:class:`~objsize.traverse.TraversalContext`.
138+
get_size_func :
139+
See :py:class:`~objsize.size.ObjSizeSettings`.
140+
get_referents_func :
141+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
142+
filter_func :
143+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
144+
exclude_modules_globals :
145+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
146+
147+
Returns
148+
-------
149+
int
150+
The objects' deep size in bytes.
151+
152+
See Also
153+
--------
154+
traverse_bfs : to understand which objects are traversed.
155+
"""
156+
settings = default_settings.replace(
157+
get_referents_func, filter_func, get_size_func, exclude, exclude_modules_globals
158+
)
159+
return settings.get_deep_size(*objs, marked_set=marked_set, exclude_set=exclude_set)
160+
161+
162+
def get_exclusive_deep_size( # pylint: disable=too-many-arguments
163+
*objs,
164+
exclude: Optional[Iterable[Any]] = None,
165+
marked_set: Optional[MarkedSet] = None,
166+
exclude_set: Optional[MarkedSet] = None,
167+
get_size_func: Optional[SizeFunc] = None,
168+
get_referents_func: Optional[GetReferentsFunc] = None,
169+
filter_func: Optional[FilterFunc] = None,
170+
exclude_modules_globals: Optional[bool] = None,
171+
) -> int:
172+
"""
173+
Calculates the deep size of all the arguments, excluding non-exclusive objects.
174+
175+
Parameters
176+
----------
177+
objs : object(s)
178+
One or more object(s).
179+
exclude :
180+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
181+
marked_set :
182+
See :py:class:`~objsize.traverse.TraversalContext`.
183+
exclude_set :
184+
See :py:class:`~objsize.traverse.TraversalContext`.
185+
get_size_func :
186+
See :py:class:`~objsize.size.ObjSizeSettings`.
187+
get_referents_func :
188+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
189+
filter_func :
190+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
191+
exclude_modules_globals :
192+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
193+
194+
Returns
195+
-------
196+
int
197+
The objects' deep size in bytes.
198+
199+
See Also
200+
--------
201+
traverse_exclusive_bfs : to understand which objects are traversed.
202+
"""
203+
settings = default_settings.replace(
204+
get_referents_func, filter_func, get_size_func, exclude, exclude_modules_globals
205+
)
206+
return settings.get_exclusive_deep_size(*objs, marked_set=marked_set, exclude_set=exclude_set)
207+
208+
209+
def get_exclude_set(
210+
exclude: Optional[Iterable[Any]] = None,
211+
exclude_set: Optional[MarkedSet] = None,
212+
get_referents_func: GetReferentsFunc = default_get_referents,
213+
filter_func: FilterFunc = default_object_filter,
214+
exclude_modules_globals: bool = False,
215+
) -> set:
216+
"""
217+
Traverse all the arguments' subtree without ingesting the result, just to update the `exclude_set`.
218+
See `traverse_bfs()` for more information.
219+
220+
:deprecated: It will be removed on version 1.0.0.
221+
222+
Parameters
223+
----------
224+
exclude :
225+
One or more object(s).
226+
exclude_set :
227+
See :py:class:`~objsize.traverse.TraversalContext`.
228+
get_referents_func :
229+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
230+
filter_func :
231+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
232+
exclude_modules_globals :
233+
See :py:class:`~objsize.traverse.ObjSizeSettings`.
234+
235+
Returns
236+
-------
237+
set
238+
The updated exclude-set.
239+
240+
Attention
241+
---------
242+
Deprecated. It will be removed on version 1.0.0.
243+
"""
244+
warnings.warn("objsize.get_exclude_set() is deprecated. It will be removed on version 1.0.0.", DeprecationWarning)
245+
settings = default_settings.replace(get_referents_func, filter_func, None, exclude, exclude_modules_globals)
246+
return settings.new_context(exclude_set=exclude_set).exclude_set

0 commit comments

Comments
 (0)