Skip to content

Commit b3fa944

Browse files
authored
Add iterable logic to notice_error (#216)
* Add iterable behavior to notice_error * Remove extra logic from record_exception. * Add testing and fix outside_transaction tests * Correct missing app_name parameter. * Fix missing status code in test.
1 parent 52e4153 commit b3fa944

File tree

8 files changed

+185
-171
lines changed

8 files changed

+185
-171
lines changed

newrelic/api/application.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515
import threading
16+
import warnings
1617

1718
import newrelic.core.config
1819
import newrelic.core.agent
@@ -113,13 +114,13 @@ def link_to_application(self, name):
113114

114115
def record_exception(self, exc=None, value=None, tb=None, params={},
115116
ignore_errors=[]):
116-
# Deprecated, but deprecation warning are handled by underlying function calls
117+
# Deprecation Warning
118+
warnings.warn((
119+
'The record_exception function is deprecated. Please use the '
120+
'new api named notice_error instead.'
121+
), DeprecationWarning)
117122

118-
if not self.active:
119-
return
120-
121-
self._agent.record_exception(self._name, exc, value, tb, params,
122-
ignore_errors)
123+
self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors)
123124

124125
def notice_error(self, error=None, attributes={}, expected=None, ignore=None, status_code=None):
125126
if not self.active:

newrelic/api/time_trace.py

Lines changed: 37 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -216,16 +216,16 @@ def _observe_exception(self, exc_info=None, ignore=None, expected=None, status_c
216216

217217
# If no exception details provided, use current exception.
218218

219-
if exc_info and None not in exc_info:
220-
exc, value, tb = exc_info
221-
else:
222-
exc, value, tb = sys.exc_info()
223-
224-
# Has to be an error to be logged.
219+
# Pull from sys.exc_info if no exception is passed
220+
if not exc_info or None in exc_info:
221+
exc_info = sys.exc_info()
225222

226-
if exc is None or value is None or tb is None:
223+
# If no exception to report, exit
224+
if not exc_info or None in exc_info:
227225
return
228226

227+
exc, value, tb = exc_info
228+
229229
module, name, fullnames, message = parse_exc_info((exc, value, tb))
230230
fullname = fullnames[0]
231231

@@ -246,7 +246,8 @@ def _observe_exception(self, exc_info=None, ignore=None, expected=None, status_c
246246
# 1. function parameter override as bool
247247
# 2. function parameter callable
248248
# 3. callable on transaction
249-
# 4. default rule matching from settings
249+
# 4. function parameter iterable of class names
250+
# 5. default rule matching from settings
250251

251252
should_ignore = None
252253
is_expected = None
@@ -270,9 +271,17 @@ def _observe_exception(self, exc_info=None, ignore=None, expected=None, status_c
270271
if should_ignore:
271272
return
272273

274+
# List of class names
275+
if should_ignore is None and ignore is not None and not callable(ignore):
276+
# Do not set should_ignore to False
277+
# This should cascade into default settings rule matching
278+
for name in fullnames:
279+
if name in ignore:
280+
return
281+
273282
# Default rule matching
274283
if should_ignore is None:
275-
should_ignore = should_ignore_error((exc, value, tb), status_code=status_code)
284+
should_ignore = should_ignore_error(exc_info, status_code=status_code)
276285
if should_ignore:
277286
return
278287

@@ -285,13 +294,18 @@ def _observe_exception(self, exc_info=None, ignore=None, expected=None, status_c
285294
if is_expected is None and callable(expected):
286295
is_expected = expected(exc, value, tb)
287296

288-
# Callable on transaction
289-
if is_expected is None and hasattr(transaction, '_expected_errors'):
290-
is_expected = transaction._expected_errors(exc, value, tb)
297+
298+
# List of class names
299+
if is_expected is None and expected is not None and not callable(expected):
300+
# Do not set is_expected to False
301+
# This should cascade into default settings rule matching
302+
for name in fullnames:
303+
if name in expected:
304+
is_expected = True
291305

292306
# Default rule matching
293307
if is_expected is None:
294-
is_expected = is_expected_error((exc, value, tb), status_code=status_code)
308+
is_expected = is_expected_error(exc_info, status_code=status_code)
295309

296310
# Record a supportability metric if error attributes are being
297311
# overiden.
@@ -343,49 +357,14 @@ def notice_error(self, error=None, attributes={}, expected=None, ignore=None, st
343357
settings, fullname, message, is_expected, custom_params, self.guid, tb)
344358

345359

346-
def record_exception(self, exc_info=None,
347-
params={}, ignore_errors=[]):
360+
def record_exception(self, exc_info=None, params={}, ignore_errors=[]):
348361
# Deprecation Warning
349362
warnings.warn((
350363
'The record_exception function is deprecated. Please use the '
351364
'new api named notice_error instead.'
352365
), DeprecationWarning)
353366

354-
transaction = self.transaction
355-
356-
# Pull from sys.exc_info if no exception is passed
357-
if not exc_info or None in exc_info:
358-
exc_info = sys.exc_info()
359-
360-
# If no exception to report, exit
361-
if not exc_info or None in exc_info:
362-
return
363-
364-
exc, value, tb = exc_info
365-
366-
# Check ignore_errors callables
367-
# We check these here separatly from the notice_error implementation
368-
# to preserve previous functionality in precedence
369-
should_ignore = None
370-
371-
if hasattr(transaction, '_ignore_errors'):
372-
should_ignore = transaction._ignore_errors(exc, value, tb)
373-
if should_ignore:
374-
return
375-
376-
if callable(ignore_errors):
377-
should_ignore = ignore_errors(exc, value, tb)
378-
if should_ignore:
379-
return
380-
381-
# Check ignore_errors iterables
382-
if should_ignore is None and not callable(ignore_errors):
383-
_, _, fullnames, _ = parse_exc_info(exc_info)
384-
for fullname in fullnames:
385-
if fullname in ignore_errors:
386-
return
387-
388-
self.notice_error(error=exc_info, attributes=params, ignore=should_ignore)
367+
self.notice_error(error=exc_info, attributes=params, ignore=ignore_errors)
389368

390369
def _add_agent_attribute(self, key, value):
391370
self.agent_attributes[key] = value
@@ -590,19 +569,16 @@ def get_linking_metadata():
590569

591570
def record_exception(exc=None, value=None, tb=None, params={},
592571
ignore_errors=[], application=None):
593-
# Deprecated, but deprecation warning are handled by underlying function calls
594-
if application is None:
595-
trace = current_trace()
596-
if trace:
597-
trace.record_exception((exc, value, tb), params,
598-
ignore_errors)
599-
else:
600-
if application.enabled:
601-
application.record_exception(exc, value, tb, params,
602-
ignore_errors)
572+
# Deprecation Warning
573+
warnings.warn((
574+
'The record_exception function is deprecated. Please use the '
575+
'new api named notice_error instead.'
576+
), DeprecationWarning)
577+
578+
notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors, application=application)
603579

604580

605-
def notice_error(error=None, attributes={}, expected=None, ignore=None, application=None, status_code=None):
581+
def notice_error(error=None, attributes={}, expected=None, ignore=None, status_code=None, application=None):
606582
if application is None:
607583
trace = current_trace()
608584
if trace:

newrelic/api/transaction.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,26 +1479,14 @@ def set_transaction_name(self, name, group=None, priority=None):
14791479
self._group = group
14801480
self._name = name
14811481

1482-
def record_exception(self, exc=None, value=None, tb=None,
1483-
params={}, ignore_errors=[]):
1484-
# Deprecated, but deprecation warning are handled by underlying function calls
1485-
settings = self._settings
1486-
1487-
if not settings:
1488-
return
1489-
1490-
if not settings.error_collector.enabled:
1491-
return
1492-
1493-
if not settings.collect_errors and not settings.collect_error_events:
1494-
return
1482+
def record_exception(self, exc=None, value=None, tb=None, params={}, ignore_errors=[]):
1483+
# Deprecation Warning
1484+
warnings.warn((
1485+
'The record_exception function is deprecated. Please use the '
1486+
'new api named notice_error instead.'
1487+
), DeprecationWarning)
14951488

1496-
current_span = trace_cache().current_trace()
1497-
if current_span:
1498-
current_span.record_exception(
1499-
(exc, value, tb),
1500-
params=params,
1501-
ignore_errors=ignore_errors)
1489+
self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors)
15021490

15031491
def notice_error(self, error=None, attributes={}, expected=None, ignore=None, status_code=None):
15041492
settings = self._settings

newrelic/core/agent.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import threading
2727
import atexit
2828
import traceback
29+
import warnings
2930

3031
import newrelic
3132
import newrelic.core.config
@@ -503,15 +504,14 @@ def remove_thread_utilization(self):
503504
from newrelic.core.thread_utilization import _utilization_trackers
504505
_utilization_trackers.clear()
505506

506-
def record_exception(self, app_name, exc=None, value=None, tb=None,
507-
params={}, ignore_errors=[]):
508-
# Deprecated, but deprecation warning are handled by underlying function calls
507+
def record_exception(self, app_name, exc=None, value=None, tb=None, params={}, ignore_errors=[]):
508+
# Deprecation Warning
509+
warnings.warn((
510+
'The record_exception function is deprecated. Please use the '
511+
'new api named notice_error instead.'
512+
), DeprecationWarning)
509513

510-
application = self._applications.get(app_name, None)
511-
if application is None or not application.active:
512-
return
513-
514-
application.record_exception(exc, value, tb, params, ignore_errors)
514+
self.notice_error(app_name, error=(exc, value, tb), attributes=params, ignore=ignore_errors)
515515

516516
def notice_error(self, app_name, error=None, attributes={}, expected=None, ignore=None, status_code=None):
517517
application = self._applications.get(app_name, None)

newrelic/core/application.py

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import os
2525
import traceback
2626
import imp
27+
import warnings
2728

2829
from functools import partial
2930

@@ -711,26 +712,18 @@ def remove_data_source(self, name):
711712

712713
self._data_samplers.remove(data_sampler)
713714

714-
def record_exception(self, exc=None, value=None, tb=None, params={},
715-
ignore_errors=[]):
715+
def record_exception(self, exc=None, value=None, tb=None, params={}, ignore_errors=[]):
716716
"""Record a global exception against the application independent
717717
of a specific transaction.
718718
719-
Deprecated, but deprecation warning are handled by underlying function calls
720719
"""
720+
# Deprecation Warning
721+
warnings.warn((
722+
'The record_exception function is deprecated. Please use the '
723+
'new api named notice_error instead.'
724+
), DeprecationWarning)
721725

722-
if not self._active_session:
723-
return
724-
725-
with self._stats_lock:
726-
# It may still actually be rejected if no exception
727-
# supplied or if was in the ignored list. For now
728-
# always attempt anyway and also increment the events
729-
# count still so that short harvest is extended.
730-
731-
self._global_events_account += 1
732-
self._stats_engine.record_exception(exc, value, tb,
733-
params, ignore_errors)
726+
self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors)
734727

735728
def notice_error(self, error=None, attributes={}, expected=None, ignore=None, status_code=None):
736729
"""Record a global exception against the application independent

newrelic/core/stats_engine.py

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -573,32 +573,7 @@ def record_exception(self, exc=None, value=None, tb=None, params={},
573573
'new api named notice_error instead.'
574574
), DeprecationWarning)
575575

576-
# Pull from sys.exc_info if no exception is passed
577-
if None in (exc, value, tb):
578-
exc, value, tb = sys.exc_info()
579-
580-
# If no exception to report, exit
581-
if None in (exc, value, tb):
582-
return
583-
584-
# Check ignore_errors callables
585-
# We check these here separatly from the notice_error implementation
586-
# to preserve previous functionality in precedence
587-
should_ignore = None
588-
589-
if callable(ignore_errors):
590-
should_ignore = ignore_errors(exc, value, tb)
591-
if should_ignore:
592-
return
593-
594-
# Check ignore_errors iterables
595-
if should_ignore is None and not callable(ignore_errors):
596-
_, _, fullnames, _ = parse_exc_info((exc, value, tb))
597-
for fullname in fullnames:
598-
if fullname in ignore_errors:
599-
return
600-
601-
self.notice_error(error=(exc, value, tb), attributes=params, ignore=should_ignore)
576+
self.notice_error(error=(exc, value, tb), attributes=params, ignore=ignore_errors)
602577

603578
def notice_error(self, error=None, attributes={}, expected=None, ignore=None, status_code=None):
604579
settings = self.__settings
@@ -624,17 +599,7 @@ def notice_error(self, error=None, attributes={}, expected=None, ignore=None, st
624599

625600
exc, value, tb = error
626601

627-
# If no exception details provided, use current exception.
628-
629-
if exc is None and value is None and tb is None:
630-
exc, value, tb = sys.exc_info()
631-
632-
# Has to be an error to be logged.
633-
634-
if exc is None or value is None or tb is None:
635-
return
636-
637-
module, name, fullnames, message = parse_exc_info((exc, value, tb))
602+
module, name, fullnames, message = parse_exc_info(error)
638603
fullname = fullnames[0]
639604

640605
# Check to see if we need to strip the message before recording it.
@@ -653,7 +618,8 @@ def notice_error(self, error=None, attributes={}, expected=None, ignore=None, st
653618
# Precedence:
654619
# 1. function parameter override as bool
655620
# 2. function parameter callable
656-
# 3. default rule matching from settings
621+
# 3. function parameter iterable of class names
622+
# 4. default rule matching from settings
657623

658624
should_ignore = None
659625
is_expected = None
@@ -671,9 +637,17 @@ def notice_error(self, error=None, attributes={}, expected=None, ignore=None, st
671637
if should_ignore:
672638
return
673639

640+
# List of class names
641+
if should_ignore is None and ignore is not None and not callable(ignore):
642+
# Do not set should_ignore to False
643+
# This should cascade into default settings rule matching
644+
for name in fullnames:
645+
if name in ignore:
646+
return
647+
674648
# Default rule matching
675649
if should_ignore is None:
676-
should_ignore = should_ignore_error((exc, value, tb), status_code=status_code)
650+
should_ignore = should_ignore_error(error, status_code=status_code)
677651
if should_ignore:
678652
return
679653

@@ -686,9 +660,18 @@ def notice_error(self, error=None, attributes={}, expected=None, ignore=None, st
686660
if is_expected is None and callable(expected):
687661
is_expected = expected(exc, value, tb)
688662

663+
664+
# List of class names
665+
if is_expected is None and expected is not None and not callable(expected):
666+
# Do not set is_expected to False
667+
# This should cascade into default settings rule matching
668+
for name in fullnames:
669+
if name in expected:
670+
is_expected = True
671+
689672
# Default rule matching
690673
if is_expected is None:
691-
is_expected = is_expected_error((exc, value, tb), status_code=status_code)
674+
is_expected = is_expected_error(error, status_code=status_code)
692675

693676
# Only add attributes if High Security Mode is off.
694677

0 commit comments

Comments
 (0)