|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
| 15 | +import fnmatch |
15 | 16 | import os
|
16 | 17 | import sys
|
17 | 18 | import logging
|
@@ -1267,19 +1268,50 @@ def _process_module_configuration():
|
1267 | 1268 | _raise_configuration_error(section)
|
1268 | 1269 |
|
1269 | 1270 |
|
| 1271 | +def _module_function_glob(module, object_path): |
| 1272 | + """Match functions and class methods in a module to file globbing syntax.""" |
| 1273 | + if not any([c in object_path for c in {"*", "?", "["}]): # Identify globbing patterns |
| 1274 | + return (object_path,) # Returned value must be iterable |
| 1275 | + else: |
| 1276 | + # Gather module functions |
| 1277 | + try: |
| 1278 | + available_functions = {k: v for k, v in module.__dict__.items() if callable(v) and not isinstance(v, type)} |
| 1279 | + except Exception: |
| 1280 | + # Default to empty dict if no functions available |
| 1281 | + available_functions = dict() |
| 1282 | + |
| 1283 | + # Gather module classes and methods |
| 1284 | + try: |
| 1285 | + available_classes = {k: v for k, v in module.__dict__.items() if isinstance(v, type)} |
| 1286 | + for cls in available_classes: |
| 1287 | + try: |
| 1288 | + # Skip adding individual class's methods on failure |
| 1289 | + available_functions.update({"%s.%s" % (cls, k): v for k, v in available_classes.get(cls).__dict__.items() if callable(v) and not isinstance(v, type)}) |
| 1290 | + except Exception: |
| 1291 | + pass |
| 1292 | + except Exception: |
| 1293 | + # Skip adding all class methods on failure |
| 1294 | + pass |
| 1295 | + |
| 1296 | + # Under the hood uses fnmatch, which uses os.path.normcase |
| 1297 | + # On windows this would cause issues with case insensitivity, |
| 1298 | + # but on all other operating systems there should be no issues. |
| 1299 | + return fnmatch.filter(available_functions, object_path) |
| 1300 | + |
| 1301 | + |
1270 | 1302 | # Setup wsgi application wrapper defined in configuration file.
|
1271 | 1303 |
|
1272 | 1304 |
|
1273 | 1305 | def _wsgi_application_import_hook(object_path, application):
|
1274 | 1306 | def _instrument(target):
|
1275 |
| - _logger.debug( |
1276 |
| - "wrap wsgi-application %s" % ((target, object_path, application),) |
1277 |
| - ) |
1278 |
| - |
1279 | 1307 | try:
|
1280 |
| - newrelic.api.wsgi_application.wrap_wsgi_application( |
1281 |
| - target, object_path, application |
1282 |
| - ) |
| 1308 | + for func in _module_function_glob(target, object_path): |
| 1309 | + _logger.debug( |
| 1310 | + "wrap wsgi-application %s" % ((target, func, application),) |
| 1311 | + ) |
| 1312 | + newrelic.api.wsgi_application.wrap_wsgi_application( |
| 1313 | + target, func, application |
| 1314 | + ) |
1283 | 1315 | except Exception:
|
1284 | 1316 | _raise_instrumentation_error("wsgi-application", locals())
|
1285 | 1317 |
|
@@ -1327,15 +1359,15 @@ def _process_wsgi_application_configuration():
|
1327 | 1359 |
|
1328 | 1360 | def _background_task_import_hook(object_path, application, name, group):
|
1329 | 1361 | def _instrument(target):
|
1330 |
| - _logger.debug( |
1331 |
| - "wrap background-task %s" |
1332 |
| - % ((target, object_path, application, name, group),) |
1333 |
| - ) |
1334 |
| - |
1335 | 1362 | try:
|
1336 |
| - newrelic.api.background_task.wrap_background_task( |
1337 |
| - target, object_path, application, name, group |
1338 |
| - ) |
| 1363 | + for func in _module_function_glob(target, object_path): |
| 1364 | + _logger.debug( |
| 1365 | + "wrap background-task %s" |
| 1366 | + % ((target, func, application, name, group),) |
| 1367 | + ) |
| 1368 | + newrelic.api.background_task.wrap_background_task( |
| 1369 | + target, func, application, name, group |
| 1370 | + ) |
1339 | 1371 | except Exception:
|
1340 | 1372 | _raise_instrumentation_error("background-task", locals())
|
1341 | 1373 |
|
@@ -1394,10 +1426,10 @@ def _process_background_task_configuration():
|
1394 | 1426 |
|
1395 | 1427 | def _database_trace_import_hook(object_path, sql):
|
1396 | 1428 | def _instrument(target):
|
1397 |
| - _logger.debug("wrap database-trace %s" % ((target, object_path, sql),)) |
1398 |
| - |
1399 | 1429 | try:
|
1400 |
| - newrelic.api.database_trace.wrap_database_trace(target, object_path, sql) |
| 1430 | + for func in _module_function_glob(target, object_path): |
| 1431 | + _logger.debug("wrap database-trace %s" % ((target, func, sql),)) |
| 1432 | + newrelic.api.database_trace.wrap_database_trace(target, func, sql) |
1401 | 1433 | except Exception:
|
1402 | 1434 | _raise_instrumentation_error("database-trace", locals())
|
1403 | 1435 |
|
@@ -1444,14 +1476,14 @@ def _process_database_trace_configuration():
|
1444 | 1476 |
|
1445 | 1477 | def _external_trace_import_hook(object_path, library, url, method):
|
1446 | 1478 | def _instrument(target):
|
1447 |
| - _logger.debug( |
1448 |
| - "wrap external-trace %s" % ((target, object_path, library, url, method),) |
1449 |
| - ) |
1450 |
| - |
1451 | 1479 | try:
|
1452 |
| - newrelic.api.external_trace.wrap_external_trace( |
1453 |
| - target, object_path, library, url, method |
1454 |
| - ) |
| 1480 | + for func in _module_function_glob(target, object_path): |
| 1481 | + _logger.debug( |
| 1482 | + "wrap external-trace %s" % ((target, func, library, url, method),) |
| 1483 | + ) |
| 1484 | + newrelic.api.external_trace.wrap_external_trace( |
| 1485 | + target, func, library, url, method |
| 1486 | + ) |
1455 | 1487 | except Exception:
|
1456 | 1488 | _raise_instrumentation_error("external-trace", locals())
|
1457 | 1489 |
|
@@ -1512,15 +1544,15 @@ def _function_trace_import_hook(
|
1512 | 1544 | object_path, name, group, label, params, terminal, rollup
|
1513 | 1545 | ):
|
1514 | 1546 | def _instrument(target):
|
1515 |
| - _logger.debug( |
1516 |
| - "wrap function-trace %s" |
1517 |
| - % ((target, object_path, name, group, label, params, terminal, rollup),) |
1518 |
| - ) |
1519 |
| - |
1520 | 1547 | try:
|
1521 |
| - newrelic.api.function_trace.wrap_function_trace( |
1522 |
| - target, object_path, name, group, label, params, terminal, rollup |
1523 |
| - ) |
| 1548 | + for func in _module_function_glob(target, object_path): |
| 1549 | + _logger.debug( |
| 1550 | + "wrap function-trace %s" |
| 1551 | + % ((target, func, name, group, label, params, terminal, rollup),) |
| 1552 | + ) |
| 1553 | + newrelic.api.function_trace.wrap_function_trace( |
| 1554 | + target, func, name, group, label, params, terminal, rollup |
| 1555 | + ) |
1524 | 1556 | except Exception:
|
1525 | 1557 | _raise_instrumentation_error("function-trace", locals())
|
1526 | 1558 |
|
@@ -1588,12 +1620,12 @@ def _process_function_trace_configuration():
|
1588 | 1620 |
|
1589 | 1621 | def _generator_trace_import_hook(object_path, name, group):
|
1590 | 1622 | def _instrument(target):
|
1591 |
| - _logger.debug("wrap generator-trace %s" % ((target, object_path, name, group),)) |
1592 |
| - |
1593 | 1623 | try:
|
1594 |
| - newrelic.api.generator_trace.wrap_generator_trace( |
1595 |
| - target, object_path, name, group |
1596 |
| - ) |
| 1624 | + for func in _module_function_glob(target, object_path): |
| 1625 | + _logger.debug("wrap generator-trace %s" % ((target, func, name, group),)) |
| 1626 | + newrelic.api.generator_trace.wrap_generator_trace( |
| 1627 | + target, func, name, group |
| 1628 | + ) |
1597 | 1629 | except Exception:
|
1598 | 1630 | _raise_instrumentation_error("generator-trace", locals())
|
1599 | 1631 |
|
@@ -1648,14 +1680,14 @@ def _process_generator_trace_configuration():
|
1648 | 1680 |
|
1649 | 1681 | def _profile_trace_import_hook(object_path, name, group, depth):
|
1650 | 1682 | def _instrument(target):
|
1651 |
| - _logger.debug( |
1652 |
| - "wrap profile-trace %s" % ((target, object_path, name, group, depth),) |
1653 |
| - ) |
1654 |
| - |
1655 | 1683 | try:
|
1656 |
| - newrelic.api.profile_trace.wrap_profile_trace( |
1657 |
| - target, object_path, name, group, depth=depth |
1658 |
| - ) |
| 1684 | + for func in _module_function_glob(target, object_path): |
| 1685 | + _logger.debug( |
| 1686 | + "wrap profile-trace %s" % ((target, func, name, group, depth),) |
| 1687 | + ) |
| 1688 | + newrelic.api.profile_trace.wrap_profile_trace( |
| 1689 | + target, func, name, group, depth=depth |
| 1690 | + ) |
1659 | 1691 | except Exception:
|
1660 | 1692 | _raise_instrumentation_error("profile-trace", locals())
|
1661 | 1693 |
|
@@ -1714,12 +1746,12 @@ def _process_profile_trace_configuration():
|
1714 | 1746 |
|
1715 | 1747 | def _memcache_trace_import_hook(object_path, command):
|
1716 | 1748 | def _instrument(target):
|
1717 |
| - _logger.debug("wrap memcache-trace %s" % ((target, object_path, command),)) |
1718 |
| - |
1719 | 1749 | try:
|
1720 |
| - newrelic.api.memcache_trace.wrap_memcache_trace( |
1721 |
| - target, object_path, command |
1722 |
| - ) |
| 1750 | + for func in _module_function_glob(target, object_path): |
| 1751 | + _logger.debug("wrap memcache-trace %s" % ((target, func, command),)) |
| 1752 | + newrelic.api.memcache_trace.wrap_memcache_trace( |
| 1753 | + target, func, command |
| 1754 | + ) |
1723 | 1755 | except Exception:
|
1724 | 1756 | _raise_instrumentation_error("memcache-trace", locals())
|
1725 | 1757 |
|
@@ -1768,14 +1800,14 @@ def _process_memcache_trace_configuration():
|
1768 | 1800 |
|
1769 | 1801 | def _transaction_name_import_hook(object_path, name, group, priority):
|
1770 | 1802 | def _instrument(target):
|
1771 |
| - _logger.debug( |
1772 |
| - "wrap transaction-name %s" % ((target, object_path, name, group, priority),) |
1773 |
| - ) |
1774 |
| - |
1775 | 1803 | try:
|
1776 |
| - newrelic.api.transaction_name.wrap_transaction_name( |
1777 |
| - target, object_path, name, group, priority |
1778 |
| - ) |
| 1804 | + for func in _module_function_glob(target, object_path): |
| 1805 | + _logger.debug( |
| 1806 | + "wrap transaction-name %s" % ((target, func, name, group, priority),) |
| 1807 | + ) |
| 1808 | + newrelic.api.transaction_name.wrap_transaction_name( |
| 1809 | + target, func, name, group, priority |
| 1810 | + ) |
1779 | 1811 | except Exception:
|
1780 | 1812 | _raise_instrumentation_error("transaction-name", locals())
|
1781 | 1813 |
|
@@ -1837,12 +1869,12 @@ def _process_transaction_name_configuration():
|
1837 | 1869 |
|
1838 | 1870 | def _error_trace_import_hook(object_path, ignore, expected):
|
1839 | 1871 | def _instrument(target):
|
1840 |
| - _logger.debug("wrap error-trace %s" % ((target, object_path, ignore, expected),)) |
1841 |
| - |
1842 | 1872 | try:
|
1843 |
| - newrelic.api.error_trace.wrap_error_trace( |
1844 |
| - target, object_path, ignore, expected, None |
1845 |
| - ) |
| 1873 | + for func in _module_function_glob(target, object_path): |
| 1874 | + _logger.debug("wrap error-trace %s" % ((target, func, ignore, expected),)) |
| 1875 | + newrelic.api.error_trace.wrap_error_trace( |
| 1876 | + target, func, ignore, expected, None |
| 1877 | + ) |
1846 | 1878 | except Exception:
|
1847 | 1879 | _raise_instrumentation_error("error-trace", locals())
|
1848 | 1880 |
|
@@ -2009,15 +2041,15 @@ def _setup_data_source():
|
2009 | 2041 |
|
2010 | 2042 | def _function_profile_import_hook(object_path, filename, delay, checkpoint):
|
2011 | 2043 | def _instrument(target):
|
2012 |
| - _logger.debug( |
2013 |
| - "wrap function-profile %s" |
2014 |
| - % ((target, object_path, filename, delay, checkpoint),) |
2015 |
| - ) |
2016 |
| - |
2017 | 2044 | try:
|
2018 |
| - newrelic.api.function_profile.wrap_function_profile( |
2019 |
| - target, object_path, filename, delay, checkpoint |
2020 |
| - ) |
| 2045 | + for func in _module_function_glob(target, object_path): |
| 2046 | + _logger.debug( |
| 2047 | + "wrap function-profile %s" |
| 2048 | + % ((target, func, filename, delay, checkpoint),) |
| 2049 | + ) |
| 2050 | + newrelic.api.function_profile.wrap_function_profile( |
| 2051 | + target, func, filename, delay, checkpoint |
| 2052 | + ) |
2021 | 2053 | except Exception:
|
2022 | 2054 | _raise_instrumentation_error("function-profile", locals())
|
2023 | 2055 |
|
|
0 commit comments