whatap-python 1.8.5__tar.gz → 1.8.7__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 (135) hide show
  1. {whatap_python-1.8.5 → whatap_python-1.8.7}/PKG-INFO +1 -1
  2. {whatap_python-1.8.5 → whatap_python-1.8.7}/setup.py +1 -1
  3. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/__init__.py +29 -11
  4. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/agent/darwin/amd64/whatap_python +0 -0
  5. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/agent/darwin/arm64/whatap_python +0 -0
  6. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/agent/linux/amd64/whatap_python +0 -0
  7. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/agent/linux/arm64/whatap_python +0 -0
  8. whatap_python-1.8.7/whatap/build.py +4 -0
  9. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/conf/configuration.py +5 -0
  10. whatap_python-1.8.7/whatap/counter/__init__.py +9 -0
  11. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/scripts/__init__.py +5 -1
  12. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_wsgi.py +24 -7
  13. whatap_python-1.8.7/whatap/trace/mod/database_neo4j.py +126 -0
  14. whatap_python-1.8.7/whatap/trace/mod/standalone_multiple.py +278 -0
  15. whatap_python-1.8.7/whatap/trace/mod/standalone_single.py +123 -0
  16. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/trace_module_definition.py +7 -0
  17. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap_python.egg-info/PKG-INFO +1 -1
  18. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap_python.egg-info/SOURCES.txt +3 -0
  19. whatap_python-1.8.5/whatap/build.py +0 -4
  20. whatap_python-1.8.5/whatap/counter/__init__.py +0 -6
  21. {whatap_python-1.8.5 → whatap_python-1.8.7}/README.md +0 -0
  22. {whatap_python-1.8.5 → whatap_python-1.8.7}/setup.cfg +0 -0
  23. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/LICENSE +0 -0
  24. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/README.rst +0 -0
  25. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/__main__.py +0 -0
  26. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/bootstrap/__init__.py +0 -0
  27. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/bootstrap/sitecustomize.py +0 -0
  28. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/conf/__init__.py +0 -0
  29. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/conf/configure.py +0 -0
  30. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/conf/license.py +0 -0
  31. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/control/__init__.py +0 -0
  32. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/counter/counter_manager.py +0 -0
  33. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/counter/tasks/__init__.py +0 -0
  34. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/counter/tasks/openfiledescriptor.py +0 -0
  35. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/io/__init__.py +0 -0
  36. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/io/data_inputx.py +0 -0
  37. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/io/data_outputx.py +0 -0
  38. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/__init__.py +0 -0
  39. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/async_sender.py +0 -0
  40. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/packet_enum.py +0 -0
  41. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/packet_type_enum.py +0 -0
  42. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/param_def.py +0 -0
  43. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/stackhelper.py +0 -0
  44. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/udp_session.py +0 -0
  45. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/net/udp_thread.py +0 -0
  46. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/pack/__init__.py +0 -0
  47. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/pack/logSinkPack.py +0 -0
  48. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/pack/pack.py +0 -0
  49. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/pack/pack_enum.py +0 -0
  50. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/pack/tagCountPack.py +0 -0
  51. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/__init__.py +0 -0
  52. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/__init__.py +0 -0
  53. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/amqp_kombu.py +0 -0
  54. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/amqp_pika.py +0 -0
  55. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_bottle.py +0 -0
  56. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_celery.py +0 -0
  57. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_cherrypy.py +0 -0
  58. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_django.py +0 -0
  59. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_django_asgi.py +0 -0
  60. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_django_py3.py +0 -0
  61. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_fastapi.py +0 -0
  62. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_flask.py +0 -0
  63. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_frappe.py +0 -0
  64. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_graphql.py +0 -0
  65. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_nameko.py +0 -0
  66. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_odoo.py +0 -0
  67. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_starlette.py +0 -0
  68. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/application_tornado.py +0 -0
  69. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_cxoracle.py +0 -0
  70. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_mongo.py +0 -0
  71. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_mysql.py +0 -0
  72. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_postgresql.py +0 -0
  73. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_redis.py +0 -0
  74. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/database_toolkit.py +0 -0
  75. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/email_smtp.py +0 -0
  76. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/httpc_django.py +0 -0
  77. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/httpc_httplib.py +0 -0
  78. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/httpc_requests.py +0 -0
  79. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/httpc_urllib3.py +0 -0
  80. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/logging.py +0 -0
  81. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/mod/plugin.py +0 -0
  82. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/simple_trace_context.py +0 -0
  83. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/trace_context.py +0 -0
  84. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/trace_context_manager.py +0 -0
  85. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/trace/trace_import.py +0 -0
  86. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/__init__.py +0 -0
  87. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/bit_util.py +0 -0
  88. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/cardinality/__init__.py +0 -0
  89. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/cardinality/hyperloglog.py +0 -0
  90. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/cardinality/murmurhash.py +0 -0
  91. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/cardinality/registerset.py +0 -0
  92. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/compare_util.py +0 -0
  93. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/date_util.py +0 -0
  94. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/debug_util.py +0 -0
  95. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/escape_literal_sql.py +0 -0
  96. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/hash_util.py +0 -0
  97. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/hexa32.py +0 -0
  98. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/int_set.py +0 -0
  99. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/ip_util.py +0 -0
  100. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/keygen.py +0 -0
  101. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/linked_list.py +0 -0
  102. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/linked_map.py +0 -0
  103. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/metering_util.py +0 -0
  104. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/request_double_queue.py +0 -0
  105. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/request_queue.py +0 -0
  106. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/string_util.py +0 -0
  107. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/throttle_util.py +0 -0
  108. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/util/userid_util.py +0 -0
  109. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/__init__.py +0 -0
  110. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/blob_value.py +0 -0
  111. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/boolean_value.py +0 -0
  112. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/decimal_value.py +0 -0
  113. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/double_summary.py +0 -0
  114. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/double_value.py +0 -0
  115. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/float_array.py +0 -0
  116. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/float_value.py +0 -0
  117. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/int_array.py +0 -0
  118. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/ip4_value.py +0 -0
  119. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/list_value.py +0 -0
  120. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/long_array.py +0 -0
  121. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/long_summary.py +0 -0
  122. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/map_value.py +0 -0
  123. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/null_value.py +0 -0
  124. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/number_value.py +0 -0
  125. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/summary_value.py +0 -0
  126. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/text_array.py +0 -0
  127. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/text_hash_value.py +0 -0
  128. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/text_value.py +0 -0
  129. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/value.py +0 -0
  130. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/value/value_enum.py +0 -0
  131. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap/whatap.conf +0 -0
  132. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap_python.egg-info/dependency_links.txt +0 -0
  133. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap_python.egg-info/entry_points.txt +0 -0
  134. {whatap_python-1.8.5 → whatap_python-1.8.7}/whatap_python.egg-info/not-zip-safe +0 -0
  135. {whatap_python-1.8.5 → whatap_python-1.8.7}/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.5
3
+ Version: 1.8.7
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,41 @@ 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
+
56
+ """
57
+ 현재 preview_whatap_conf 를 사용중인 옵션
58
+ - ignore_whatap_stdout (False)
59
+ - standalone_enabled (False)
60
+ - open_file_descriptor_enabled (False)
61
+ """
62
+ value = 'false'
55
63
  try:
56
64
  with open(whatap_config) as f:
57
65
  for raw in f:
58
66
  line = raw.strip()
59
67
  if not line or line.startswith('#'):
60
68
  continue
61
- if line.startswith('ignore_whatap_stdout'):
69
+ if line.startswith(option_name):
62
70
  parts = line.split('=', 1)
63
71
  if len(parts) == 2:
64
- ignore_whatap_stdout = parts[1].strip()
72
+ value = parts[1].strip()
65
73
  break
66
- return ignore_whatap_stdout
74
+ return value
67
75
 
68
76
  except FileNotFoundError:
69
- return ignore_whatap_stdout
77
+ return value
70
78
 
71
79
  except Exception as e:
72
80
  print(f'WHATAP: config parse error ({e!r})')
73
- return ignore_whatap_stdout
81
+ return value
74
82
 
75
83
 
76
84
 
77
- ignore_whatap_stdout = read_ignore_whatap_stdout()
85
+ ignore_whatap_stdout = preview_whatap_conf("ignore_whatap_stdout")
78
86
 
79
87
 
80
88
 
@@ -329,6 +337,14 @@ def hooks(home):
329
337
  'trace',
330
338
  'mod',
331
339
  key)}
340
+
341
+ if conf.standalone_enabled:
342
+ if conf.standalone_type == 'multiple-transaction':
343
+ from whatap.trace.mod.standalone_multiple import instrument_standalone_multiple
344
+ instrument_standalone_multiple()
345
+ else:
346
+ from whatap.trace.mod.standalone_single import instrument_standalone_single
347
+ instrument_standalone_single()
332
348
 
333
349
  except Exception as e:
334
350
  logging.debug(e, extra={'id': 'PLUGIN ERROR'})
@@ -354,9 +370,11 @@ def agent():
354
370
  if write_file(home, home.lower(), whatap_home):
355
371
  os.environ['WHATAP_HOME'] = whatap_home
356
372
 
357
- # t = threading.Thread(target=go)
358
- # t.setDaemon(True)
359
- # t.start()
373
+ whatap_code_start = preview_whatap_conf("whatap_code_start")
374
+ if whatap_code_start == 'true':
375
+ t = threading.Thread(target=go)
376
+ t.setDaemon(True)
377
+ t.start()
360
378
  config(home)
361
379
 
362
380
  ARCH = {
@@ -0,0 +1,4 @@
1
+ app = 'Python'
2
+ name = 'whatap-python'
3
+ version = '1.8.7'
4
+ release_date = '20250729'
@@ -1,5 +1,6 @@
1
1
  Configuration = {
2
2
  "dev": False,
3
+ "whatap_code_start": False,
3
4
  "ignore_whatap_stdout" : False,
4
5
  "net_udp_port": "6600",
5
6
  "web_static_content_extensions": "js, htm, html, gif, png, jpg, css, swf, ico",
@@ -50,6 +51,10 @@ Configuration = {
50
51
  "stat_error_max_count": 1000,
51
52
  "stat_useragent_max_count": 500,
52
53
 
54
+ "standalone_enabled" : False,
55
+ "standalone_type" : "single-transaction",
56
+ "standalone_transaction_patterns" : "",
57
+
53
58
  "user_header_ticket_enabled": False,
54
59
  "user_header_ticket":"",
55
60
  "trace_user_cookie_limit":2048,
@@ -0,0 +1,9 @@
1
+ from .counter_manager import CounterMgr # CounterMgr 클래스 import
2
+ from whatap import preview_whatap_conf
3
+
4
+ open_file_descriptor_enabled = preview_whatap_conf("open_file_descriptor_enabled")
5
+
6
+ if open_file_descriptor_enabled != 'false':
7
+ mgr = CounterMgr()
8
+ mgr.setDaemon(True)
9
+ mgr.start()
@@ -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)