whatap-python 1.8.4__tar.gz → 1.8.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of whatap-python might be problematic. Click here for more details.

Files changed (134) hide show
  1. {whatap_python-1.8.4 → whatap_python-1.8.6}/PKG-INFO +1 -1
  2. {whatap_python-1.8.4 → whatap_python-1.8.6}/setup.py +1 -1
  3. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/__init__.py +22 -8
  4. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/agent/darwin/amd64/whatap_python +0 -0
  5. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/agent/darwin/arm64/whatap_python +0 -0
  6. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/agent/linux/amd64/whatap_python +0 -0
  7. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/agent/linux/arm64/whatap_python +0 -0
  8. whatap_python-1.8.6/whatap/build.py +4 -0
  9. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/conf/configuration.py +4 -0
  10. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/scripts/__init__.py +5 -1
  11. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_wsgi.py +24 -7
  12. whatap_python-1.8.6/whatap/trace/mod/database_neo4j.py +126 -0
  13. whatap_python-1.8.6/whatap/trace/mod/standalone_multiple.py +278 -0
  14. whatap_python-1.8.6/whatap/trace/mod/standalone_single.py +123 -0
  15. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/trace_module_definition.py +7 -0
  16. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/PKG-INFO +1 -1
  17. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/SOURCES.txt +3 -0
  18. whatap_python-1.8.4/whatap/build.py +0 -4
  19. {whatap_python-1.8.4 → whatap_python-1.8.6}/README.md +0 -0
  20. {whatap_python-1.8.4 → whatap_python-1.8.6}/setup.cfg +0 -0
  21. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/LICENSE +0 -0
  22. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/README.rst +0 -0
  23. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/__main__.py +0 -0
  24. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/bootstrap/__init__.py +0 -0
  25. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/bootstrap/sitecustomize.py +0 -0
  26. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/conf/__init__.py +0 -0
  27. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/conf/configure.py +0 -0
  28. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/conf/license.py +0 -0
  29. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/control/__init__.py +0 -0
  30. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/counter/__init__.py +0 -0
  31. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/counter/counter_manager.py +0 -0
  32. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/counter/tasks/__init__.py +0 -0
  33. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/counter/tasks/openfiledescriptor.py +0 -0
  34. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/io/__init__.py +0 -0
  35. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/io/data_inputx.py +0 -0
  36. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/io/data_outputx.py +0 -0
  37. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/__init__.py +0 -0
  38. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/async_sender.py +0 -0
  39. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/packet_enum.py +0 -0
  40. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/packet_type_enum.py +0 -0
  41. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/param_def.py +0 -0
  42. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/stackhelper.py +0 -0
  43. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/udp_session.py +0 -0
  44. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/net/udp_thread.py +0 -0
  45. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/pack/__init__.py +0 -0
  46. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/pack/logSinkPack.py +0 -0
  47. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/pack/pack.py +0 -0
  48. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/pack/pack_enum.py +0 -0
  49. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/pack/tagCountPack.py +0 -0
  50. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/__init__.py +0 -0
  51. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/__init__.py +0 -0
  52. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/amqp_kombu.py +0 -0
  53. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/amqp_pika.py +0 -0
  54. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_bottle.py +0 -0
  55. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_celery.py +0 -0
  56. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_cherrypy.py +0 -0
  57. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_django.py +0 -0
  58. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_django_asgi.py +0 -0
  59. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_django_py3.py +0 -0
  60. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_fastapi.py +0 -0
  61. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_flask.py +0 -0
  62. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_frappe.py +0 -0
  63. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_graphql.py +0 -0
  64. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_nameko.py +0 -0
  65. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_odoo.py +0 -0
  66. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_starlette.py +0 -0
  67. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/application_tornado.py +0 -0
  68. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_cxoracle.py +0 -0
  69. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_mongo.py +0 -0
  70. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_mysql.py +0 -0
  71. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_postgresql.py +0 -0
  72. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_redis.py +0 -0
  73. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/database_toolkit.py +0 -0
  74. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/email_smtp.py +0 -0
  75. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/httpc_django.py +0 -0
  76. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/httpc_httplib.py +0 -0
  77. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/httpc_requests.py +0 -0
  78. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/httpc_urllib3.py +0 -0
  79. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/logging.py +0 -0
  80. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/mod/plugin.py +0 -0
  81. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/simple_trace_context.py +0 -0
  82. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/trace_context.py +0 -0
  83. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/trace_context_manager.py +0 -0
  84. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/trace/trace_import.py +0 -0
  85. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/__init__.py +0 -0
  86. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/bit_util.py +0 -0
  87. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/cardinality/__init__.py +0 -0
  88. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/cardinality/hyperloglog.py +0 -0
  89. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/cardinality/murmurhash.py +0 -0
  90. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/cardinality/registerset.py +0 -0
  91. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/compare_util.py +0 -0
  92. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/date_util.py +0 -0
  93. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/debug_util.py +0 -0
  94. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/escape_literal_sql.py +0 -0
  95. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/hash_util.py +0 -0
  96. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/hexa32.py +0 -0
  97. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/int_set.py +0 -0
  98. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/ip_util.py +0 -0
  99. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/keygen.py +0 -0
  100. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/linked_list.py +0 -0
  101. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/linked_map.py +0 -0
  102. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/metering_util.py +0 -0
  103. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/request_double_queue.py +0 -0
  104. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/request_queue.py +0 -0
  105. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/string_util.py +0 -0
  106. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/throttle_util.py +0 -0
  107. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/util/userid_util.py +0 -0
  108. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/__init__.py +0 -0
  109. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/blob_value.py +0 -0
  110. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/boolean_value.py +0 -0
  111. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/decimal_value.py +0 -0
  112. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/double_summary.py +0 -0
  113. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/double_value.py +0 -0
  114. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/float_array.py +0 -0
  115. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/float_value.py +0 -0
  116. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/int_array.py +0 -0
  117. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/ip4_value.py +0 -0
  118. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/list_value.py +0 -0
  119. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/long_array.py +0 -0
  120. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/long_summary.py +0 -0
  121. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/map_value.py +0 -0
  122. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/null_value.py +0 -0
  123. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/number_value.py +0 -0
  124. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/summary_value.py +0 -0
  125. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/text_array.py +0 -0
  126. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/text_hash_value.py +0 -0
  127. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/text_value.py +0 -0
  128. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/value.py +0 -0
  129. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/value/value_enum.py +0 -0
  130. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap/whatap.conf +0 -0
  131. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/dependency_links.txt +0 -0
  132. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/entry_points.txt +0 -0
  133. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/not-zip-safe +0 -0
  134. {whatap_python-1.8.4 → whatap_python-1.8.6}/whatap_python.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whatap-python
3
- Version: 1.8.4
3
+ Version: 1.8.6
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -18,7 +18,7 @@ setup(name=build.name,
18
18
  author_email='admin@whatap.io',
19
19
  license='Whatap License',
20
20
  url='https://www.whatap.io',
21
- packages=find_packages(),
21
+ packages=find_packages(exclude=('sample','sample.*')),
22
22
  package_data={
23
23
  'whatap': ['LICENSE', '*.rst', '*.conf', '*.json', 'agent/*/*/whatap_python']
24
24
  },
@@ -48,33 +48,39 @@ LOG_FILE_NAME = 'whatap-hook.log'
48
48
 
49
49
  isFrappeCommands = "get-frappe-commands" in sys.argv if hasattr(sys, "argv") else False
50
50
 
51
- def read_ignore_whatap_stdout():
52
- ignore_whatap_stdout = 'false'
51
+ def preview_whatap_conf(option_name:str):
53
52
  home = os.environ.get('WHATAP_HOME', '.')
54
53
  whatap_config = os.path.join(home, 'whatap.conf')
54
+
55
+ #기본 default 값 설정
56
+ if option_name == "ignore_whatap_stdout":
57
+ value = 'false'
58
+ elif option_name == "standalone_enabled":
59
+ value = 'false'
60
+
55
61
  try:
56
62
  with open(whatap_config) as f:
57
63
  for raw in f:
58
64
  line = raw.strip()
59
65
  if not line or line.startswith('#'):
60
66
  continue
61
- if line.startswith('ignore_whatap_stdout'):
67
+ if line.startswith(option_name):
62
68
  parts = line.split('=', 1)
63
69
  if len(parts) == 2:
64
- ignore_whatap_stdout = parts[1].strip()
70
+ value = parts[1].strip()
65
71
  break
66
- return ignore_whatap_stdout
72
+ return value
67
73
 
68
74
  except FileNotFoundError:
69
- return ignore_whatap_stdout
75
+ return value
70
76
 
71
77
  except Exception as e:
72
78
  print(f'WHATAP: config parse error ({e!r})')
73
- return ignore_whatap_stdout
79
+ return value
74
80
 
75
81
 
76
82
 
77
- ignore_whatap_stdout = read_ignore_whatap_stdout()
83
+ ignore_whatap_stdout = preview_whatap_conf("ignore_whatap_stdout")
78
84
 
79
85
 
80
86
 
@@ -329,6 +335,14 @@ def hooks(home):
329
335
  'trace',
330
336
  'mod',
331
337
  key)}
338
+
339
+ if conf.standalone_enabled:
340
+ if conf.standalone_type == 'multiple-transaction':
341
+ from whatap.trace.mod.standalone_multiple import instrument_standalone_multiple
342
+ instrument_standalone_multiple()
343
+ else:
344
+ from whatap.trace.mod.standalone_single import instrument_standalone_single
345
+ instrument_standalone_single()
332
346
 
333
347
  except Exception as e:
334
348
  logging.debug(e, extra={'id': 'PLUGIN ERROR'})
@@ -0,0 +1,4 @@
1
+ app = 'Python'
2
+ name = 'whatap-python'
3
+ version = '1.8.6'
4
+ release_date = '20250715'
@@ -50,6 +50,10 @@ Configuration = {
50
50
  "stat_error_max_count": 1000,
51
51
  "stat_useragent_max_count": 500,
52
52
 
53
+ "standalone_enabled" : False,
54
+ "standalone_type" : "single-transaction",
55
+ "standalone_transaction_patterns" : "",
56
+
53
57
  "user_header_ticket_enabled": False,
54
58
  "user_header_ticket":"",
55
59
  "trace_user_cookie_limit":2048,
@@ -1,11 +1,12 @@
1
1
  import os
2
2
  import re
3
+ import time
3
4
  from functools import wraps
4
5
 
5
6
  import sys, threading
6
7
 
7
8
  from whatap import check_whatap_home, ROOT_DIR, init_config, update_config, \
8
- batch_agent, AGENT_NAME, go, configPort
9
+ batch_agent, AGENT_NAME, go, configPort, preview_whatap_conf
9
10
 
10
11
 
11
12
  def whatap_command(func):
@@ -73,6 +74,9 @@ def start_agent():
73
74
 
74
75
  try:
75
76
  go(opts={'whatap.port': str(port)})
77
+ standalone_enabled = preview_whatap_conf("standalone_enabled")
78
+ if standalone_enabled == 'true':
79
+ time.sleep(1)
76
80
  except Exception as e:
77
81
  print('WHATAP: AGENT ERROR: {}'.format(e))
78
82
  print('WHATAP: continue to start user application')
@@ -444,22 +444,39 @@ def addQuoteList(arg_list):
444
444
 
445
445
  return tuple(quoted_list)
446
446
 
447
+ def neo4jQuery(query,paremeter):
448
+ transformed_query = query
449
+
450
+ for key, value in paremeter.items():
451
+ placeholder = f"${key}"
452
+ replacement = f"'{str(value)}'"
453
+ transformed_query = transformed_query.replace(placeholder, replacement)
454
+
455
+ return transformed_query
447
456
 
448
457
  def interceptor_db_execute(fn, db_info, *args, **kwargs):
449
458
  ctx = TraceContextManager.getLocalContext()
450
459
  # sendDebugProfile(ctx, 'interceptor_db_execute step -1')
451
460
  self = args[0]
461
+ db_type = db_info.get('type')
452
462
  query = None
453
- if len(args) > 2 and type(args[2]) == dict and args[2]:
454
- try:
455
- query = args[1] % addQuoteDict(args[2])
456
- except Exception as e:
457
- pass
458
- if len(args) > 2 and type(args[2]) in (list, tuple) and args[2]:
463
+
464
+ if db_type == "neo4j":
459
465
  try:
460
- query = args[1] % addQuoteList(args[2])
466
+ query = neo4jQuery(args[1], kwargs)
461
467
  except Exception as e:
462
468
  pass
469
+ else:
470
+ if len(args) > 2 and type(args[2]) == dict and args[2]:
471
+ try:
472
+ query = args[1] % addQuoteDict(args[2])
473
+ except Exception as e:
474
+ pass
475
+ if len(args) > 2 and type(args[2]) in (list, tuple) and args[2]:
476
+ try:
477
+ query = args[1] % addQuoteList(args[2])
478
+ except Exception as e:
479
+ pass
463
480
  try:
464
481
  if not query:
465
482
  query = args[1].decode()
@@ -0,0 +1,126 @@
1
+ from whatap.trace import get_dict
2
+ from whatap.trace.mod.application_wsgi import (
3
+ trace_handler,
4
+ interceptor_db_con,
5
+ interceptor_db_execute,
6
+ interceptor_db_close
7
+ )
8
+ db_info = {}
9
+
10
+ def get_db_info(session):
11
+ db_info = {'type' : 'neo4j'}
12
+
13
+ pool = getattr(session, '_pool', None)
14
+
15
+ host = None
16
+ port = None
17
+ user = None
18
+ db_name = None
19
+
20
+ try:
21
+ if pool:
22
+ addr = getattr(pool, 'address', getattr(pool, '_address', None))
23
+ if addr:
24
+ host, port = addr[0], addr[1]
25
+ except Exception:
26
+ pass
27
+ db_info["host"] = f"{host}:{port}"
28
+
29
+ try:
30
+ if pool:
31
+ auth_token = pool.get_auth()
32
+ if auth_token:
33
+ user = getattr(auth_token, 'principal', None)
34
+ except Exception as e:
35
+ pass
36
+
37
+ if user == None:
38
+ db_info["user"] = "neo4j"
39
+ else:
40
+ db_info["user"] = user
41
+
42
+ try:
43
+ session_config = getattr(session, '_config', None)
44
+ if session_config:
45
+ db_name = getattr(session_config, 'database', None)
46
+ except Exception:
47
+ pass
48
+
49
+ if db_name == None:
50
+ db_info["dbname"] = "default"
51
+ else:
52
+ db_info["dbname"] = db_name
53
+
54
+
55
+
56
+ return db_info
57
+
58
+
59
+
60
+
61
+ def instrument_neo4j(module):
62
+ orig = module.Session.run
63
+
64
+ def wrapper(fn):
65
+ @trace_handler(fn)
66
+ def trace(session, *args, **kwargs):
67
+ db_info = get_db_info(session)
68
+ try:
69
+ setattr(session, 'rowcount', -1)
70
+ except Exception as e:
71
+ raise e
72
+ callback = interceptor_db_execute(fn, db_info, session, *args, **kwargs)
73
+
74
+ return callback
75
+ return trace
76
+
77
+ module.Session.run = wrapper(orig)
78
+
79
+
80
+
81
+
82
+ orig = module.Session.close
83
+
84
+ def wrapper(fn):
85
+ @trace_handler(fn)
86
+ def trace(session, *args, **kwargs):
87
+ callback = interceptor_db_close(fn, session ,*args, **kwargs)
88
+ return callback
89
+ return trace
90
+
91
+ module.Session.close = wrapper(orig)
92
+
93
+
94
+
95
+
96
+
97
+ def wrapper(fn):
98
+ @trace_handler(fn)
99
+ def trace(tx, *args, **kwargs):
100
+ session = None
101
+ try:
102
+ session = tx._on_closed.__self__
103
+ except AttributeError:
104
+ return fn(tx, *args, **kwargs)
105
+
106
+ db_info = get_db_info(session)
107
+ try:
108
+ setattr(tx, 'rowcount', -1)
109
+ except Exception:
110
+ pass
111
+ callback = interceptor_db_execute(fn, db_info, tx, *args, **kwargs)
112
+ return callback
113
+
114
+ return trace
115
+
116
+ tx_classes_to_patch = ['Transaction', 'ManagedTransaction', 'BoltTransaction']
117
+
118
+ for class_name in tx_classes_to_patch:
119
+ if hasattr(module, class_name):
120
+ TxClass = getattr(module, class_name)
121
+ if hasattr(TxClass, 'run'):
122
+ original_run = getattr(TxClass, 'run')
123
+ setattr(TxClass, 'run', wrapper(original_run))
124
+
125
+
126
+
@@ -0,0 +1,278 @@
1
+ import sys
2
+ import atexit
3
+ import time
4
+ import traceback
5
+
6
+ import whatap.net.async_sender as async_sender
7
+
8
+ from functools import wraps
9
+
10
+ from whatap.conf.configure import Configure as conf
11
+ from whatap.util.date_util import DateUtil
12
+ from whatap.trace.trace_context import TraceContext
13
+ from whatap.trace.trace_context_manager import TraceContextManager
14
+ from whatap.net.packet_type_enum import PacketTypeEnum
15
+ from whatap.trace.mod.application_wsgi import trace_handler
16
+ from whatap import logging
17
+
18
+ def trace_handler(fn, start=False, preload=None):
19
+ def handler(func):
20
+ @wraps(func)
21
+ def wrapper(*args, **kwargs):
22
+ if preload:
23
+ preload(*args, **kwargs)
24
+
25
+ ctx = TraceContextManager.getLocalContext()
26
+ if not start and not ctx:
27
+ return fn(*args, **kwargs)
28
+ try:
29
+ callback = func(*args, **kwargs)
30
+ except Exception as e:
31
+ if ctx and ctx.error_step == e:
32
+ ctx.error_step = None
33
+ raise e
34
+ raise
35
+ else:
36
+ if ctx and ctx.error_step:
37
+ e = ctx.error_step
38
+ ctx.error_step = None
39
+ raise e
40
+ return callback
41
+
42
+ return wrapper
43
+
44
+ return handler
45
+
46
+ def load_transaction_patterns():
47
+ raw = conf.standalone_transaction_patterns
48
+ patterns = set(entry.strip() for entry in raw.split(",") if entry.strip())
49
+
50
+ return patterns
51
+
52
+
53
+ def shutdown_agent():
54
+
55
+ start_time = time.time()
56
+
57
+ while not async_sender.q.empty():
58
+ if time.time() - start_time > 3.0:
59
+ break
60
+ time.sleep(0.1)
61
+
62
+ if async_sender.q.empty():
63
+ return
64
+ else:
65
+ remaining_items = async_sender.q.qsize()
66
+
67
+ def end_interceptor(ctx):
68
+ if not ctx:
69
+ return
70
+
71
+ if conf.dev:
72
+ logging.debug(f'end transaction id(seq): {ctx.id}', extra={'id': 'WA112'})
73
+ print(f'end transaction id(seq): {ctx.id}', dict(extra={'id': 'WA112'}))
74
+
75
+ start_time = DateUtil.nowSystem()
76
+ ctx.start_time = start_time
77
+
78
+ datas = [ctx.host, ctx.service_name, ctx.mtid, ctx.mdepth, ctx.mcaller_txid,
79
+ ctx.mcaller_pcode, ctx.mcaller_spec, str(ctx.mcaller_url_hash), ctx.mcaller_poid, ctx.status]
80
+
81
+ ctx.elapsed = DateUtil.nowSystem() - start_time
82
+
83
+ async_sender.send_packet(PacketTypeEnum.TX_END, ctx, datas)
84
+
85
+
86
+ def start_interceptor(ctx):
87
+ if conf.dev:
88
+ logging.debug(f'start transaction id(seq): {ctx.id}', extra={'id': 'WA111'})
89
+ print(f'start transaction id(seq): {ctx.id}', dict(extra={'id': 'WA111'}))
90
+
91
+ start_time = DateUtil.nowSystem()
92
+ ctx.start_time = start_time
93
+
94
+ datas = [ctx.host, ctx.service_name, ctx.remoteIp, ctx.userAgentString,
95
+ ctx.referer, ctx.userid, ctx.isStaticContents, ctx.http_method]
96
+
97
+ async_sender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
98
+
99
+ def error_interceptor(error_msg,error_type,ctx):
100
+ if not ctx:
101
+ ctx = TraceContextManager.getLocalContext()
102
+ if not ctx:
103
+ return
104
+ if not ctx.error:
105
+ ctx.error = 1
106
+
107
+ error = ''
108
+ errors = []
109
+ errors.append(error_type)
110
+ errors.append(error_msg)
111
+
112
+ frame = sys._current_frames().get(ctx.thread.ident)
113
+ if not frame:
114
+ return
115
+
116
+ for stack in traceback.extract_stack(frame):
117
+ line = stack[0]
118
+ line_num = stack[1]
119
+ method_name = stack[2]
120
+
121
+ if line.find('/whatap/trace') > -1 or line.find(
122
+ '/threading.py') > -1:
123
+ continue
124
+ error += '{} ({}:{})\n'.format(method_name, line, line_num)
125
+
126
+ errors.append(error)
127
+
128
+ async_sender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors)
129
+
130
+ if conf.profile_exception_stack:
131
+ desc = '\n'.join(errors)
132
+ datas = [' ', ' ', desc]
133
+ ctx.start_time = DateUtil.nowSystem()
134
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
135
+
136
+ def instrument_standalone_multiple():
137
+ atexit.register(shutdown_agent)
138
+
139
+ patterns = load_transaction_patterns()
140
+ targets_to_patch = {tuple(entry.split(":", 1)) for entry in patterns}
141
+
142
+ tracked_methods = set()
143
+ tracked_funcs = set()
144
+ modules = set()
145
+
146
+
147
+ for entry in patterns:
148
+ mod, target = entry.split(":", 1)
149
+ if "." in target:
150
+ cls, mtd = target.split(".", 1)
151
+ tracked_methods.add((mod, cls, mtd))
152
+ else:
153
+ func = target
154
+ tracked_funcs.add((mod, func))
155
+
156
+ modules.add(mod)
157
+
158
+ def wrapper(fn, module_name, target_name):
159
+ @trace_handler(fn, start=True)
160
+ def trace(*args, **kwargs):
161
+ prev_ctx = TraceContextManager.getLocalContext()
162
+ ctx = TraceContext()
163
+ ctx.service_name = f"{module_name}:{target_name}"
164
+ start_interceptor(ctx)
165
+ try:
166
+ callback = fn(*args, **kwargs)
167
+ return callback
168
+ except Exception as e:
169
+ error_msg = str(e)
170
+ error_type = e.__class__.__name__
171
+ error_interceptor(error_msg,error_type,ctx)
172
+ raise e
173
+ finally:
174
+ end_interceptor(ctx)
175
+ TraceContextManager.setLocalContext(prev_ctx)
176
+
177
+ return trace
178
+
179
+
180
+
181
+ patching_queue = []
182
+ sys_trace_current_service_name = None
183
+
184
+ def trace_and_patch_profiler(frame, event, arg):
185
+ global sys_trace_current_service_name
186
+
187
+ if not targets_to_patch and not patching_queue:
188
+ pass
189
+
190
+ module_name = frame.f_globals.get("__name__")
191
+ if module_name not in (modules) or event not in ("call", "return","exception"):
192
+ return trace_and_patch_profiler
193
+
194
+ fn_name = frame.f_code.co_name
195
+ is_method = "self" in frame.f_locals
196
+
197
+ is_target = False
198
+ full_target_name = fn_name
199
+ target_tuple = None
200
+
201
+ if is_method:
202
+ cls_name = type(frame.f_locals["self"]).__name__
203
+ full_target_name = f"{cls_name}.{fn_name}"
204
+ if (module_name, cls_name, fn_name) in tracked_methods:
205
+ is_target = True
206
+ target_tuple = (module_name, full_target_name)
207
+ else:
208
+ if (module_name, fn_name) in tracked_funcs:
209
+ is_target = True
210
+ target_tuple = (module_name, full_target_name)
211
+
212
+ if target_tuple in targets_to_patch:
213
+ if event == "call":
214
+ if not is_target:
215
+ return trace_and_patch_profiler
216
+
217
+ prev_ctx = TraceContextManager.getLocalContext()
218
+ if prev_ctx:
219
+ patching_queue.append(prev_ctx)
220
+
221
+ ctx = TraceContext()
222
+ ctx.service_name = f"{module_name}:{full_target_name}"
223
+ sys_trace_current_service_name = ctx.service_name
224
+
225
+ TraceContextManager.setLocalContext(ctx)
226
+ start_interceptor(ctx)
227
+
228
+ try:
229
+ module_obj = sys.modules[module_name]
230
+ if is_method:
231
+ cls_name, mtd_name = target_tuple[1].split('.', 1)
232
+ cls_obj = getattr(module_obj, cls_name)
233
+ fn = getattr(cls_obj, mtd_name)
234
+ wrapped_fn = wrapper(fn, module_name, target_tuple[1])
235
+ setattr(cls_obj, mtd_name, wrapped_fn)
236
+ else:
237
+ func_name = target_tuple[1]
238
+ fn = getattr(module_obj, func_name)
239
+ wrapped_fn = wrapper(fn, module_name, func_name)
240
+ setattr(module_obj, func_name, wrapped_fn)
241
+
242
+ targets_to_patch.remove(target_tuple)
243
+
244
+
245
+
246
+ except (AttributeError, KeyError) as e:
247
+ if target_tuple in targets_to_patch:
248
+ targets_to_patch.remove(target_tuple)
249
+
250
+ if event == "return":
251
+ ctx = TraceContextManager.getLocalContext()
252
+ if ctx and sys_trace_current_service_name == f"{module_name}:{full_target_name}":
253
+ end_interceptor(ctx)
254
+ if patching_queue:
255
+ prev_ctx = patching_queue.pop()
256
+ TraceContextManager.setLocalContext(prev_ctx)
257
+ sys_trace_current_service_name = prev_ctx.service_name
258
+ else:
259
+ if not(targets_to_patch):
260
+ sys.settrace(None)
261
+
262
+ if event == "exception":
263
+ ctx = TraceContextManager.getLocalContext()
264
+ if ctx and sys_trace_current_service_name == f"{module_name}:{full_target_name}":
265
+ exc_type, exc_value , tb = arg
266
+ error_interceptor(exc_value,exc_type,ctx)
267
+ end_interceptor(ctx)
268
+ if patching_queue:
269
+ prev_ctx = patching_queue.pop()
270
+ TraceContextManager.setLocalContext(prev_ctx)
271
+ sys_trace_current_service_name = prev_ctx.service_name
272
+ else:
273
+ if not (targets_to_patch):
274
+ sys.settrace(None)
275
+
276
+ return trace_and_patch_profiler
277
+
278
+ sys.settrace(trace_and_patch_profiler)
@@ -0,0 +1,123 @@
1
+ import atexit
2
+ import sys
3
+ import traceback
4
+ import time
5
+
6
+ from whatap.conf.configure import Configure as conf
7
+ from whatap.util.date_util import DateUtil
8
+ from whatap.trace.trace_context import TraceContext
9
+ from whatap.trace.trace_context_manager import TraceContextManager
10
+ import whatap.net.async_sender as async_sender
11
+ from whatap.net.packet_type_enum import PacketTypeEnum
12
+ from whatap import logging
13
+
14
+
15
+ ctx = None
16
+
17
+
18
+ def global_exception_handler(exc_type, exc_value, exc_traceback):
19
+
20
+ global ctx
21
+ traceback.print_exception(exc_type, exc_value, exc_traceback)
22
+
23
+ standalone_error(exc_value, ctx)
24
+
25
+ sys.excepthook = global_exception_handler
26
+
27
+
28
+ def standalone_error(e, ctx=None):
29
+
30
+ if not ctx:
31
+ ctx = TraceContextManager.getLocalContext()
32
+ if not ctx:
33
+ return
34
+
35
+ ctx.error_step = e
36
+ if not ctx.error:
37
+ ctx.error = 1
38
+
39
+ errors = []
40
+ errors.append(e.__class__.__name__)
41
+
42
+ error_message = str(e)
43
+ errors.append(error_message)
44
+
45
+ error_stack = ''
46
+ frame = sys._current_frames().get(ctx.thread.ident)
47
+ if not frame:
48
+ return
49
+
50
+ for stack in traceback.extract_stack(frame):
51
+ if '/whatap/trace' in stack.filename or '/threading.py' in stack.filename:
52
+ continue
53
+ error_stack += f'{stack.name} ({stack.filename}:{stack.lineno})\n'
54
+
55
+ errors.append(error_stack)
56
+ async_sender.send_packet(PacketTypeEnum.TX_ERROR, ctx, errors)
57
+ if conf.profile_exception_stack:
58
+ desc = '\n'.join(errors)
59
+ datas = [' ', ' ', desc]
60
+ ctx.start_time = DateUtil.nowSystem()
61
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
62
+
63
+
64
+
65
+
66
+ @atexit.register
67
+ def standalone_end():
68
+ global ctx
69
+ ctx = ctx
70
+
71
+ if not ctx:
72
+ return
73
+
74
+ if conf.dev:
75
+ logging.debug('end transaction id(seq): {}'.format(ctx.id),
76
+ extra={'id': 'WA112'})
77
+ print('end transaction id(seq): {}'.format(ctx.id),
78
+ dict(extra={'id': 'WA112'}))
79
+
80
+ start_time = DateUtil.nowSystem()
81
+ ctx.start_time = start_time
82
+
83
+ datas = [ctx.host, ctx.service_name, ctx.mtid, ctx.mdepth, ctx.mcaller_txid,
84
+ ctx.mcaller_pcode, ctx.mcaller_spec, str(ctx.mcaller_url_hash), ctx.mcaller_poid,ctx.status]
85
+ ctx.elapsed = DateUtil.nowSystem() - start_time
86
+
87
+ async_sender.send_packet(PacketTypeEnum.TX_END, ctx, datas)
88
+
89
+ shutdown_start_time = time.time()
90
+ while not async_sender.q.empty():
91
+ if time.time() - shutdown_start_time > 3.0:
92
+ break
93
+ time.sleep(0.1)
94
+
95
+
96
+
97
+ def instrument_standalone_single():
98
+ global ctx
99
+
100
+ ctx = TraceContext()
101
+ ctx = ctx
102
+ if conf.dev:
103
+ logging.debug('start transaction id(seq): {}'.format(ctx.id),
104
+ extra={'id': 'WA111'})
105
+ print('start transaction id(seq): {}'.format(ctx.id), dict(extra={'id': 'WA111'}))
106
+
107
+ start_time = DateUtil.nowSystem()
108
+ ctx.start_time = start_time
109
+
110
+ ctx.service_name = sys.argv[0]
111
+
112
+ datas = [ctx.host,
113
+ ctx.service_name,
114
+ ctx.remoteIp,
115
+ ctx.userAgentString,
116
+ ctx.referer,
117
+ ctx.userid,
118
+ ctx.isStaticContents,
119
+ ctx.http_method
120
+ ]
121
+
122
+
123
+ async_sender.send_packet(PacketTypeEnum.TX_START, ctx, datas)
@@ -7,6 +7,10 @@ DEFINITION = {
7
7
  'plugin': [
8
8
  ('', 'instrument_plugin'),
9
9
  ],
10
+ 'standalone': [
11
+ ('', 'instrument_standalone_single'),
12
+ ('', 'instrument_standalone_multiple')
13
+ ],
10
14
  'httpc_httplib': [
11
15
  ('httplib', 'instrument_httplib'),
12
16
  ('http.client', 'instrument_httplib'),
@@ -32,6 +36,9 @@ DEFINITION = {
32
36
  ('psycopg2._psycopg', 'instrument_psycopg2_connection'),
33
37
  ('psycopg2.extensions', 'instrument_psycopg2_extensions'),
34
38
  ],
39
+ 'database_neo4j': [
40
+ ('neo4j', 'instrument_neo4j')
41
+ ],
35
42
  'database_toolkit': [
36
43
  ('sqlalchemy.orm.session', 'instrument_sqlalchemy'),
37
44
  ('sqlalchemy.engine.default', 'instrument_sqlalchemy_engine'),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: whatap-python
3
- Version: 1.8.4
3
+ Version: 1.8.6
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
@@ -66,6 +66,7 @@ whatap/trace/mod/application_wsgi.py
66
66
  whatap/trace/mod/database_cxoracle.py
67
67
  whatap/trace/mod/database_mongo.py
68
68
  whatap/trace/mod/database_mysql.py
69
+ whatap/trace/mod/database_neo4j.py
69
70
  whatap/trace/mod/database_postgresql.py
70
71
  whatap/trace/mod/database_redis.py
71
72
  whatap/trace/mod/database_toolkit.py
@@ -76,6 +77,8 @@ whatap/trace/mod/httpc_requests.py
76
77
  whatap/trace/mod/httpc_urllib3.py
77
78
  whatap/trace/mod/logging.py
78
79
  whatap/trace/mod/plugin.py
80
+ whatap/trace/mod/standalone_multiple.py
81
+ whatap/trace/mod/standalone_single.py
79
82
  whatap/util/__init__.py
80
83
  whatap/util/bit_util.py
81
84
  whatap/util/compare_util.py
@@ -1,4 +0,0 @@
1
- app = 'Python'
2
- name = 'whatap-python'
3
- version = '1.8.4'
4
- release_date = '20250609'
File without changes
File without changes