whatap-python 1.7.8__tar.gz → 1.8.0__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 (130) hide show
  1. {whatap_python-1.7.8 → whatap_python-1.8.0}/PKG-INFO +4 -2
  2. {whatap_python-1.7.8 → whatap_python-1.8.0}/setup.py +1 -0
  3. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/README.rst +1 -1
  4. whatap_python-1.8.0/whatap/build.py +4 -0
  5. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_django.py +10 -1
  6. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_fastapi.py +46 -22
  7. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_flask.py +12 -2
  8. whatap_python-1.8.0/whatap/trace/mod/application_tornado.py +161 -0
  9. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/trace_import.py +14 -8
  10. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/PKG-INFO +4 -2
  11. whatap_python-1.7.8/whatap/build.py +0 -4
  12. whatap_python-1.7.8/whatap/trace/mod/application_tornado.py +0 -41
  13. {whatap_python-1.7.8 → whatap_python-1.8.0}/README.md +0 -0
  14. {whatap_python-1.7.8 → whatap_python-1.8.0}/setup.cfg +0 -0
  15. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/LICENSE +0 -0
  16. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/__init__.py +0 -0
  17. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/__main__.py +0 -0
  18. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/agent/darwin/amd64/whatap_python +0 -0
  19. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/agent/darwin/arm64/whatap_python +0 -0
  20. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/agent/linux/amd64/whatap_python +0 -0
  21. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/agent/linux/arm64/whatap_python +0 -0
  22. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/bootstrap/__init__.py +0 -0
  23. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/bootstrap/sitecustomize.py +0 -0
  24. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/conf/__init__.py +0 -0
  25. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/conf/configuration.py +0 -0
  26. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/conf/configure.py +0 -0
  27. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/conf/license.py +0 -0
  28. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/control/__init__.py +0 -0
  29. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/counter/__init__.py +0 -0
  30. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/counter/counter_manager.py +0 -0
  31. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/counter/tasks/__init__.py +0 -0
  32. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/counter/tasks/openfiledescriptor.py +0 -0
  33. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/io/__init__.py +0 -0
  34. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/io/data_inputx.py +0 -0
  35. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/io/data_outputx.py +0 -0
  36. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/__init__.py +0 -0
  37. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/async_sender.py +0 -0
  38. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/packet_enum.py +0 -0
  39. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/packet_type_enum.py +0 -0
  40. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/param_def.py +0 -0
  41. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/stackhelper.py +0 -0
  42. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/udp_session.py +0 -0
  43. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/net/udp_thread.py +0 -0
  44. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/pack/__init__.py +0 -0
  45. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/pack/logSinkPack.py +0 -0
  46. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/pack/pack.py +0 -0
  47. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/pack/pack_enum.py +0 -0
  48. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/pack/tagCountPack.py +0 -0
  49. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/scripts/__init__.py +0 -0
  50. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/__init__.py +0 -0
  51. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/__init__.py +0 -0
  52. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/amqp_kombu.py +0 -0
  53. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/amqp_pika.py +0 -0
  54. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_bottle.py +0 -0
  55. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_celery.py +0 -0
  56. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_cherrypy.py +0 -0
  57. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_django_asgi.py +0 -0
  58. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_django_py3.py +0 -0
  59. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_frappe.py +0 -0
  60. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_graphql.py +0 -0
  61. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_nameko.py +0 -0
  62. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/application_wsgi.py +0 -0
  63. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_cxoracle.py +0 -0
  64. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_mongo.py +0 -0
  65. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_mysql.py +0 -0
  66. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_postgresql.py +0 -0
  67. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_redis.py +0 -0
  68. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/database_toolkit.py +0 -0
  69. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/email_smtp.py +0 -0
  70. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/httpc_django.py +0 -0
  71. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/httpc_httplib.py +0 -0
  72. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/httpc_requests.py +0 -0
  73. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/httpc_urllib3.py +0 -0
  74. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/logging.py +0 -0
  75. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/mod/plugin.py +0 -0
  76. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/simple_trace_context.py +0 -0
  77. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/trace_context.py +0 -0
  78. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/trace_context_manager.py +0 -0
  79. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/trace/trace_module_definition.py +0 -0
  80. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/__init__.py +0 -0
  81. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/bit_util.py +0 -0
  82. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/cardinality/__init__.py +0 -0
  83. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/cardinality/hyperloglog.py +0 -0
  84. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/cardinality/murmurhash.py +0 -0
  85. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/cardinality/registerset.py +0 -0
  86. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/compare_util.py +0 -0
  87. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/date_util.py +0 -0
  88. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/debug_util.py +0 -0
  89. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/escape_literal_sql.py +0 -0
  90. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/hash_util.py +0 -0
  91. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/hexa32.py +0 -0
  92. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/int_set.py +0 -0
  93. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/ip_util.py +0 -0
  94. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/keygen.py +0 -0
  95. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/linked_list.py +0 -0
  96. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/linked_map.py +0 -0
  97. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/metering_util.py +0 -0
  98. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/request_double_queue.py +0 -0
  99. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/request_queue.py +0 -0
  100. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/string_util.py +0 -0
  101. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/throttle_util.py +0 -0
  102. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/util/userid_util.py +0 -0
  103. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/__init__.py +0 -0
  104. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/blob_value.py +0 -0
  105. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/boolean_value.py +0 -0
  106. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/decimal_value.py +0 -0
  107. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/double_summary.py +0 -0
  108. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/double_value.py +0 -0
  109. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/float_array.py +0 -0
  110. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/float_value.py +0 -0
  111. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/int_array.py +0 -0
  112. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/ip4_value.py +0 -0
  113. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/list_value.py +0 -0
  114. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/long_array.py +0 -0
  115. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/long_summary.py +0 -0
  116. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/map_value.py +0 -0
  117. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/null_value.py +0 -0
  118. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/number_value.py +0 -0
  119. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/summary_value.py +0 -0
  120. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/text_array.py +0 -0
  121. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/text_hash_value.py +0 -0
  122. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/text_value.py +0 -0
  123. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/value.py +0 -0
  124. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/value/value_enum.py +0 -0
  125. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap/whatap.conf +0 -0
  126. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/SOURCES.txt +0 -0
  127. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/dependency_links.txt +0 -0
  128. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/entry_points.txt +0 -0
  129. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/not-zip-safe +0 -0
  130. {whatap_python-1.7.8 → whatap_python-1.8.0}/whatap_python.egg-info/top_level.txt +0 -0
@@ -1,16 +1,18 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: whatap-python
3
- Version: 1.7.8
3
+ Version: 1.8.0
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
7
7
  Author-email: admin@whatap.io
8
8
  License: Whatap License
9
+ Requires-Python: >=3.7
9
10
  Dynamic: author
10
11
  Dynamic: author-email
11
12
  Dynamic: description
12
13
  Dynamic: home-page
13
14
  Dynamic: license
15
+ Dynamic: requires-python
14
16
  Dynamic: summary
15
17
 
16
18
 
@@ -23,7 +25,7 @@ WhaTap_ for python
23
25
 
24
26
  - Whatap allows for application performance monitoring.
25
27
  - Support: WSGI server application & Batch job & Specific method profiling.
26
- - Python version : 2.7 + & 3.3+
28
+ - Python version : 3.7+
27
29
 
28
30
  Installation
29
31
  ------------
@@ -33,5 +33,6 @@ setup(name=build.name,
33
33
  ],
34
34
  },
35
35
  zip_safe=False,
36
+ python_requires='>=3.7',
36
37
  )
37
38
 
@@ -8,7 +8,7 @@ WhaTap_ for python
8
8
 
9
9
  - Whatap allows for application performance monitoring.
10
10
  - Support: WSGI server application & Batch job & Specific method profiling.
11
- - Python version : 2.7 + & 3.3+
11
+ - Python version : 3.7+
12
12
 
13
13
  Installation
14
14
  ------------
@@ -0,0 +1,4 @@
1
+ app = 'Python'
2
+ name = 'whatap-python'
3
+ version = '1.8.0'
4
+ release_date = '20250414'
@@ -45,8 +45,17 @@ def instrument(module):
45
45
  @trace_handler(fn, True)
46
46
  @blocking_handler()
47
47
  def trace(*args, **kwargs):
48
- callback = interceptor(fn, *args, **kwargs)
48
+ django_instance = args[0]
49
+ environ = args[1]
50
+ original_start_response = args[2]
51
+
52
+ def custom_start_response(status, response_headers, exc_info=None):
53
+ ctx = TraceContextManager.getLocalContext()
54
+ ctx.status = status[:3]
55
+ return original_start_response(status, response_headers, exc_info)
49
56
 
57
+ new_args = (django_instance, environ, custom_start_response)
58
+ callback = interceptor(fn, *new_args, **kwargs)
50
59
  return callback
51
60
 
52
61
  return trace
@@ -28,6 +28,23 @@ _RESPONSE='response'
28
28
  _REMOTE_ADDR='remoteAddr'
29
29
  _COOKIE='cookie'
30
30
 
31
+ async def sse_body_wrapper(original_iterator, ctx,environ, response):
32
+ try:
33
+ async for chunk in original_iterator:
34
+ yield chunk
35
+ except Exception as e:
36
+ interceptor_step_error(e)
37
+ raise
38
+ finally:
39
+ if ctx:
40
+ if conf.profile_http_header_enabled:
41
+ sendHeaders(ctx, environ)
42
+ if response and conf.trace_user_enabled:
43
+ if not conf.trace_user_using_ip:
44
+ setUserId(environ, response, ctx._rawuserid)
45
+ end_interceptor(ctx=ctx)
46
+
47
+
31
48
  def getUserId(headers, defValue):
32
49
  try:
33
50
  if conf.user_header_ticket:
@@ -36,7 +53,7 @@ def getUserId(headers, defValue):
36
53
  return hash_util.hashFromString(ticket), ticket
37
54
  return 0,""
38
55
  cookie = headers.get("cookie")
39
-
56
+
40
57
  if cookie:
41
58
  if len(cookie) >= conf.trace_user_cookie_limit :
42
59
  return defValue
@@ -74,12 +91,12 @@ def sendHeaders(ctx, environ):
74
91
  for key, value in environ.items():
75
92
  keys.append(key)
76
93
  keys.sort()
77
-
94
+
78
95
  text = ''
79
96
  for key in keys:
80
97
  text += '{}={}\n'.format(key,
81
98
  environ[key])
82
-
99
+
83
100
  datas = ['HTTP-HEADERS', 'HTTP-HEADERS', text]
84
101
  ctx.start_time = DateUtil.nowSystem()
85
102
  async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
@@ -88,7 +105,7 @@ def setUserId(environ, res, cookieValue):
88
105
  try:
89
106
  if not conf.user_header_ticket:
90
107
  cookie = environ.get(_COOKIE)
91
-
108
+
92
109
  if not cookie or cookie.find(userid_util.WHATAP_R) < 0 or cookie.find(cookieValue) < 0:
93
110
  res.set_cookie(key=userid_util.WHATAP_R, value=cookieValue, \
94
111
  max_age=bit_util.INT_MAX_VALUE, path="/", \
@@ -118,7 +135,7 @@ def interceptor_error_log(trxid, e, fn, args, kwargs):
118
135
  lastlineno = lineno
119
136
  lastf_globals = fr.f_globals
120
137
 
121
- fields = {'errorClass': errorClass,
138
+ fields = {'errorClass': errorClass,
122
139
  'args': str(inspect.getcallargs(fn, *args, **kwargs))}
123
140
  if lastfilename and lastlineno:
124
141
  fields['filename'] = lastfilename
@@ -133,7 +150,7 @@ def interceptor_error_log(trxid, e, fn, args, kwargs):
133
150
  error += ''.join([indicator, l.lstrip()])
134
151
  else:
135
152
  error += l
136
-
153
+
137
154
  p = logSinkPack.getLogSinkPack(
138
155
  t = DateUtil.now(),
139
156
  category = "UnhandledException",
@@ -146,7 +163,7 @@ def interceptor_error_log(trxid, e, fn, args, kwargs):
146
163
  bout = whatapio.DataOutputX()
147
164
  bout.writePack(p, None)
148
165
  packbytes = bout.toByteArray()
149
-
166
+
150
167
  async_sender.send_relaypack(packbytes)
151
168
 
152
169
  def interceptor(fn, dependant, *args, **kwargs):
@@ -158,7 +175,7 @@ def interceptor(fn, dependant, *args, **kwargs):
158
175
  environ = whatap_dict.get('headers')
159
176
  ctx.host = environ.get('host')
160
177
  ctx.service_name = dependant.path
161
-
178
+
162
179
  ctx.remoteIp = getRemoteAddr(environ, whatap_dict)
163
180
 
164
181
  ctx.userAgentString = environ.get('user_agent')
@@ -172,7 +189,7 @@ def interceptor(fn, dependant, *args, **kwargs):
172
189
 
173
190
  mstt = environ.get('{}'.format(
174
191
  conf._trace_mtrace_caller_key), '')
175
-
192
+
176
193
  if mstt:
177
194
  ctx.setTransfer(mstt)
178
195
  if conf.stat_mtrace_enabled:
@@ -188,7 +205,7 @@ def interceptor(fn, dependant, *args, **kwargs):
188
205
  ctx.setTxid(myid)
189
206
  caller_poid = environ.get('{}'.format(
190
207
  conf._trace_mtrace_caller_poid_key), '')
191
-
208
+
192
209
  if caller_poid:
193
210
  ctx.mcaller_poid = caller_poid
194
211
 
@@ -200,7 +217,7 @@ def interceptor(fn, dependant, *args, **kwargs):
200
217
  pass
201
218
 
202
219
  start_interceptor(ctx)
203
-
220
+
204
221
  try:
205
222
  callback = fn(*args, **kwargs)
206
223
  ctx = TraceContextManager.getLocalContext()
@@ -219,7 +236,7 @@ def interceptor(fn, dependant, *args, **kwargs):
219
236
  if hasattr(callback, 'reason_phrase'):
220
237
  errors.insert(0, callback.reason_phrase)
221
238
  interceptor_error(status_code, errors)
222
-
239
+
223
240
  return callback
224
241
  except Exception as e:
225
242
  interceptor_step_error(e)
@@ -230,7 +247,7 @@ def interceptor(fn, dependant, *args, **kwargs):
230
247
  if conf.profile_http_header_enabled:
231
248
  sendHeaders(ctx, environ)
232
249
  response = whatap_dict.get(_RESPONSE)
233
-
250
+
234
251
  if response and conf.trace_user_enabled:
235
252
  if not conf.trace_user_using_ip:
236
253
  setUserId(environ, response, ctx._rawuserid )
@@ -241,11 +258,11 @@ def interceptor(fn, dependant, *args, **kwargs):
241
258
  async def interceptor_async(fn, dependant, *args, **kwargs):
242
259
  if not hasattr(dependant, _WHATAP_DICT):
243
260
  return await fn(*args, **kwargs)
244
-
261
+
245
262
  ctx = TraceContextManager.getLocalContext()
246
-
263
+
247
264
  ctx.service_name = dependant.path
248
-
265
+
249
266
  whatap_dict = getattr(dependant, _WHATAP_DICT)
250
267
  environ = whatap_dict.get('headers')
251
268
  ctx.host = environ.get('host')
@@ -262,7 +279,7 @@ async def interceptor_async(fn, dependant, *args, **kwargs):
262
279
 
263
280
  mstt = environ.get('{}'.format(
264
281
  conf._trace_mtrace_caller_key), '')
265
-
282
+
266
283
  if mstt:
267
284
  ctx.setTransfer(mstt)
268
285
  if conf.stat_mtrace_enabled:
@@ -278,7 +295,7 @@ async def interceptor_async(fn, dependant, *args, **kwargs):
278
295
  ctx.setTxid(myid)
279
296
  caller_poid = environ.get('{}'.format(
280
297
  conf._trace_mtrace_caller_poid_key), '')
281
-
298
+
282
299
  if caller_poid:
283
300
  ctx.mcaller_poid = caller_poid
284
301
 
@@ -288,12 +305,19 @@ async def interceptor_async(fn, dependant, *args, **kwargs):
288
305
  return await fn(*args, **kwargs)
289
306
  except Exception as e:
290
307
  pass
291
-
308
+
292
309
  start_interceptor(ctx)
293
-
310
+ callback = None
311
+
294
312
  try:
295
313
  callback = await fn(*args, **kwargs)
314
+ from fastapi.responses import StreamingResponse
296
315
  ctx = TraceContextManager.getLocalContext()
316
+
317
+ if isinstance(callback, StreamingResponse) and hasattr(callback, "body_iterator"):
318
+ original_iter = callback.body_iterator
319
+ callback.body_iterator = sse_body_wrapper(original_iter, ctx, environ,whatap_dict.get(_RESPONSE))
320
+
297
321
  if ctx:
298
322
  query_string = "&".join([str(query) for query in dependant.query_params])
299
323
  if query_string:
@@ -309,7 +333,7 @@ async def interceptor_async(fn, dependant, *args, **kwargs):
309
333
  if hasattr(callback, 'reason_phrase'):
310
334
  errors.insert(0, callback.reason_phrase)
311
335
  interceptor_error(status_code, errors)
312
-
336
+
313
337
  return callback
314
338
  except Exception as e:
315
339
  interceptor_step_error(e)
@@ -317,7 +341,7 @@ async def interceptor_async(fn, dependant, *args, **kwargs):
317
341
  raise e
318
342
  finally:
319
343
  ctx = TraceContextManager.getLocalContext()
320
- if ctx:
344
+ if ctx and not isinstance(callback, StreamingResponse):
321
345
  if conf.profile_http_header_enabled:
322
346
  sendHeaders(ctx, environ)
323
347
  response = whatap_dict.get(_RESPONSE)
@@ -1,12 +1,22 @@
1
1
  from whatap.trace.mod.application_wsgi import interceptor, trace_handler, \
2
2
  interceptor_error
3
-
3
+ from whatap.trace.trace_context_manager import TraceContextManager
4
4
 
5
5
  def instrument(module):
6
6
  def wrapper(fn):
7
7
  @trace_handler(fn, True)
8
8
  def trace(*args, **kwargs):
9
- callback = interceptor(fn, *args, **kwargs)
9
+ flask_instance = args[0]
10
+ environ = args[1]
11
+ original_start_response = args[2]
12
+
13
+ def custom_start_response(status, response_headers, exc_info=None):
14
+ ctx = TraceContextManager.getLocalContext()
15
+ ctx.status = status[:3]
16
+ return original_start_response(status, response_headers, exc_info)
17
+
18
+ new_args = (flask_instance, environ, custom_start_response)
19
+ callback = interceptor(fn, *new_args, **kwargs)
10
20
  return callback
11
21
 
12
22
  return trace
@@ -0,0 +1,161 @@
1
+ import inspect
2
+ import whatap.net.async_sender as async_sender
3
+ from whatap.net.packet_type_enum import PacketTypeEnum
4
+ from whatap.util.userid_util import UseridUtil as userid_util
5
+ from whatap.trace.trace_context import TraceContext
6
+ from whatap.trace.trace_context_manager import TraceContextManager
7
+ from whatap.util.date_util import DateUtil
8
+ from whatap.conf.configure import Configure as conf
9
+ from whatap.trace.mod.application_wsgi import trace_handler, \
10
+ start_interceptor, end_interceptor, interceptor_error, isIgnore
11
+
12
+
13
+ def parseServiceName(environ):
14
+ return environ.get('PATH_INFO', '')
15
+
16
+
17
+ def instrument(module):
18
+ def wrapper(fn):
19
+ async def trace(*args, **kwargs):
20
+ request = args[0].request
21
+ environ = {
22
+ 'HTTP_HOST': request.host,
23
+ 'PATH_INFO': request.path,
24
+ 'QUERY_STRING': request.query_arguments,
25
+ 'REMOTE_ADDR': request.remote_ip,
26
+ 'HTTP_USER_AGENT': request.headers.get('User-Agent', ''),
27
+ 'HTTP_REFERER': request.headers.get('Referer', ''),
28
+ 'REQUEST_METHOD': request.method
29
+ }
30
+
31
+ for header_name, value in request.headers.items():
32
+ key = 'HTTP_' + header_name.upper().replace('-', '_')
33
+ environ[key] = value
34
+
35
+ async def run():
36
+ await interceptor((fn, environ), *args, **kwargs)
37
+
38
+ from tornado.ioloop import IOLoop
39
+ IOLoop.current().add_callback(run)
40
+
41
+ return None
42
+
43
+ return trace
44
+
45
+ module.RequestHandler._execute = wrapper(module.RequestHandler._execute)
46
+
47
+ def wrapper(fn):
48
+ @trace_handler(fn)
49
+ def trace(*args, **kwargs):
50
+ callback = fn(*args, **kwargs)
51
+
52
+ e = args[1]
53
+ status_code = args[0]._status_code
54
+ errors = [e.__class__.__name__, str(e)]
55
+ interceptor_error(status_code, errors)
56
+ return callback
57
+
58
+ return trace
59
+
60
+ module.RequestHandler._handle_request_exception = wrapper(
61
+ module.RequestHandler._handle_request_exception)
62
+
63
+
64
+ async def interceptor(rn_environ, *args, **kwargs):
65
+ if not isinstance(rn_environ, tuple):
66
+ rn_environ = (rn_environ, args[1])
67
+ fn, environ = rn_environ
68
+
69
+ ctx = TraceContext()
70
+ ctx.host = environ.get('HTTP_HOST', '').split(':')[0]
71
+ ctx.service_name = parseServiceName(environ)
72
+ ctx.http_method = environ.get('REQUEST_METHOD', '')
73
+ ctx.remoteIp = userid_util.getRemoteAddr(args)
74
+ ctx.userAgentString = environ.get('HTTP_USER_AGENT', '')
75
+ ctx.referer = environ.get('HTTP_REFERER', '')
76
+
77
+ if conf.trace_user_enabled:
78
+ if conf.trace_user_using_ip:
79
+ ctx.userid = userid_util.getRemoteAddr(args)
80
+ else:
81
+ ctx.userid, ctx._rawuserid = userid_util.getUserId(args, ctx.remoteIp)
82
+
83
+ mstt = environ.get('HTTP_{}'.format(
84
+ conf._trace_mtrace_caller_key.upper().replace('-', '_')), '')
85
+
86
+ if mstt:
87
+ ctx.setTransfer(mstt)
88
+ if conf.stat_mtrace_enabled:
89
+ val = environ.get('HTTP_{}'.format(
90
+ conf._trace_mtrace_info_key.upper().replace('-', '_')), '')
91
+ if val and len(val):
92
+ ctx.setTransferInfo(val)
93
+ pass
94
+
95
+ myid = environ.get('HTTP_{}'.format(
96
+ conf._trace_mtrace_callee_key.upper().replace('-', '_')), '')
97
+ if myid:
98
+ ctx.setTxid(myid)
99
+ caller_poid = environ.get('HTTP_{}'.format(
100
+ conf._trace_mtrace_caller_poid_key.upper().replace('-', '_')), '')
101
+
102
+ if caller_poid:
103
+ ctx.mcaller_poid = caller_poid
104
+
105
+ try:
106
+ if isIgnore(ctx.service_name):
107
+ ctx.is_ignored = True
108
+ TraceContextManager.end(ctx.id)
109
+ callback = fn(*args, **kwargs)
110
+ if inspect.isawaitable(callback):
111
+ return await callback
112
+ return callback
113
+ except Exception:
114
+ pass
115
+
116
+ start_interceptor(ctx)
117
+
118
+ try:
119
+ callback = fn(*args, **kwargs)
120
+ if inspect.isawaitable(callback):
121
+ callback = await callback
122
+
123
+ query_string = environ.get('QUERY_STRING', '')
124
+ if query_string:
125
+ ctx.service_name += '?{}'.format(query_string)
126
+
127
+ if ctx.service_name.find('.') > -1 and ctx.service_name.split('.')[
128
+ 1] in conf.web_static_content_extensions:
129
+ ctx.isStaticContents = 'true'
130
+
131
+ handler = args[0]
132
+ status_code = getattr(handler, '_status_code', 200)
133
+ if status_code >= 400:
134
+ errors = [
135
+ callback.__class__.__name__ if callback else 'Unknown',
136
+ getattr(callback, 'reason_phrase', '')
137
+ ]
138
+ interceptor_error(status_code, errors, ctx=ctx)
139
+
140
+ else:
141
+ ctx.status = status_code
142
+
143
+ if conf.profile_http_header_enabled:
144
+ keys = []
145
+ for key, value in environ.items():
146
+ if key.startswith('HTTP_'):
147
+ keys.append(key)
148
+ keys.sort()
149
+
150
+ text = ''
151
+ for key in keys:
152
+ text += '{}={}\n'.format(key.split('HTTP_')[1].lower(),
153
+ environ[key])
154
+
155
+ datas = ['HTTP-HEADERS', 'HTTP-HEADERS', text]
156
+ ctx.start_time = DateUtil.nowSystem()
157
+ async_sender.send_packet(PacketTypeEnum.TX_MSG, ctx, datas)
158
+
159
+ return callback
160
+ finally:
161
+ end_interceptor(ctx=ctx)
@@ -2,6 +2,7 @@ import sys
2
2
 
3
3
  try:
4
4
  from importlib.util import find_spec
5
+ from importlib.abc import MetaPathFinder
5
6
  except ImportError:
6
7
  find_spec = None
7
8
 
@@ -10,6 +11,7 @@ from whatap.trace.trace_module_definition import IMPORT_HOOKS, PLUGIN
10
11
  from whatap import logging
11
12
  from whatap.conf.configure import Configure as conf
12
13
 
14
+
13
15
  def load_module(module, fullname):
14
16
  # if conf.dev:
15
17
  # logging.debug(fullname)
@@ -36,24 +38,27 @@ def load_module(module, fullname):
36
38
  finally:
37
39
  return module
38
40
 
41
+
39
42
  class _ImportHookLoader(object):
40
43
  def load_module(self, fullname):
41
44
  module = sys.modules[fullname]
42
45
  return load_module(module, fullname)
43
46
 
47
+
44
48
  class _ImportHookChainedLoader(object):
45
49
  def __init__(self, loader):
46
50
  self.loader = loader
47
-
51
+
48
52
  def load_module(self, fullname):
49
53
  module = self.loader.load_module(fullname)
50
54
  return load_module(module, fullname)
51
55
 
52
- class ImportFinder(object):
56
+
57
+ class ImportFinder(MetaPathFinder):
53
58
  def __init__(self):
54
59
  self._hooks = {}
55
-
56
- def find_module(self, fullname, path=None):
60
+
61
+ def find_spec(self, fullname, path=None, target=None):
57
62
  if fullname not in IMPORT_HOOKS \
58
63
  or fullname.startswith('whatap') \
59
64
  or fullname.startswith('pip'):
@@ -66,19 +71,20 @@ class ImportFinder(object):
66
71
  if fullname in self._hooks:
67
72
  return None
68
73
  self._hooks[fullname] = True
69
-
74
+
70
75
  # if conf.dev:
71
76
  # logging.debug(fullname)
72
-
77
+
73
78
  try:
74
79
  if find_spec:
75
80
  spec = find_spec(fullname, path)
76
81
  if spec and spec.loader:
77
- return _ImportHookChainedLoader(spec.loader)
82
+ spec.loader = _ImportHookChainedLoader(spec.loader)
83
+ return spec
78
84
  else:
79
85
  __import__(fullname)
80
86
  return _ImportHookLoader()
81
-
87
+
82
88
  except Exception as e:
83
89
  if conf.dev:
84
90
  print(e)
@@ -1,16 +1,18 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: whatap-python
3
- Version: 1.7.8
3
+ Version: 1.8.0
4
4
  Summary: Monitoring and Profiling Service
5
5
  Home-page: https://www.whatap.io
6
6
  Author: whatap
7
7
  Author-email: admin@whatap.io
8
8
  License: Whatap License
9
+ Requires-Python: >=3.7
9
10
  Dynamic: author
10
11
  Dynamic: author-email
11
12
  Dynamic: description
12
13
  Dynamic: home-page
13
14
  Dynamic: license
15
+ Dynamic: requires-python
14
16
  Dynamic: summary
15
17
 
16
18
 
@@ -23,7 +25,7 @@ WhaTap_ for python
23
25
 
24
26
  - Whatap allows for application performance monitoring.
25
27
  - Support: WSGI server application & Batch job & Specific method profiling.
26
- - Python version : 2.7 + & 3.3+
28
+ - Python version : 3.7+
27
29
 
28
30
  Installation
29
31
  ------------
@@ -1,4 +0,0 @@
1
- app = 'Python'
2
- name = 'whatap-python'
3
- version = '1.7.8'
4
- release_date = '20250324'
@@ -1,41 +0,0 @@
1
- from whatap.trace.mod.application_wsgi import trace_handler, \
2
- interceptor, interceptor_error
3
-
4
-
5
- def instrument(module):
6
- def wrapper(fn):
7
- @trace_handler(fn, True)
8
- def trace(*args, **kwargs):
9
- request = args[0].request
10
-
11
- environ = dict()
12
- environ['HTTP_HOST'] = request.host
13
- environ['PATH_INFO'] = request.path
14
- environ['QUERY_STRING'] = request.query_arguments
15
- environ['REMOTE_ADDR'] = request.remote_ip
16
- environ['HTTP_USER_AGENT'] = request.headers.get('User-Agent', '')
17
- environ['HTTP_REFERER'] = ''
18
-
19
- callback = interceptor((fn, environ), *args, **kwargs)
20
-
21
- return callback
22
-
23
- return trace
24
-
25
- module.RequestHandler._execute = wrapper(module.RequestHandler._execute)
26
-
27
- def wrapper(fn):
28
- @trace_handler(fn)
29
- def trace(*args, **kwargs):
30
- callback = fn(*args, **kwargs)
31
-
32
- e = args[1]
33
- status_code = args[0]._status_code
34
- errors = [e.__class__.__name__, str(e)]
35
- interceptor_error(status_code, errors)
36
- return callback
37
-
38
- return trace
39
-
40
- module.RequestHandler._handle_request_exception = wrapper(
41
- module.RequestHandler._handle_request_exception)
File without changes
File without changes