hi @lwintergerst ,
Thanks for your reply. Appreciate your help !!
Here is the Code Snippet where am trying to INJECT ELASTIC CODE into my Application (Custom Instrumentation)
###############################################################
# Copyright (c) 2002 **Zope Foundation** and Contributors.
###############################################################
"""Python Object Publisher -- Publish Python objects on web servers
"""
import os
import sys
from thread import allocate_lock
import transaction
from urlparse import urlparse
from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
from six import reraise
from zExceptions import Redirect
from zope.event import notify
from zope.globalrequest import setRequest, clearRequest
from zope.publisher.interfaces import ISkinnable
from zope.publisher.interfaces.browser import IBrowserPage
from zope.publisher.skinnable import setDefaultSkin
from zope.security.management import newInteraction, endInteraction
from ZPublisher.mapply import mapply
from ZPublisher import pubevents
from ZPublisher import Retry
from ZPublisher.HTTPRequest import HTTPRequest as Request
from ZPublisher.HTTPResponse import HTTPResponse as Response
from ZPublisher.utils import recordMetaData
####### ELASTIC APM INTEGRATION #######
from elasticapm import Client
import elasticapm
#import elasticapm.instrumentation.control
#from elasticapm.base import Client
#from elasticapm.conf import constants, setup_logging
#from elasticapm.handlers.logging import LoggingHandler
#from elasticapm.traces import execution_context
#from elasticapm.utils.disttracing import TraceParent
#from elasticapm.utils.logging import get_logger
#logger = get_logger("elasticapm.errors.client")
client = elasticapm.Client(service_name="Zope-POCWQAAPM51-5003-Aug25", framework_name="Zope", framework_version="4.0", server_url="http://172.27.2.33:8200")
#client = elasticapm.Client(service_name="Zope-POCWQAAPM51-5003-maapply", framework_name="Zope", framework_version="4.0", server_url="http://172.27.2.33:8200")
elasticapm.instrumentation.control.instrument()
_default_debug_mode = False
_default_realm = None
def call_object(object, args, request):
return object(*args)
def missing_name(name, request):
if name == 'self':
return request['PARENTS'][0]
request.response.badRequestError(name)
def dont_publish_class(klass, request):
request.response.forbiddenError("class %s" % klass.__name__)
def validate_user(request, user):
newSecurityManager(request, user)
def set_default_debug_mode(debug_mode):
global _default_debug_mode
_default_debug_mode = debug_mode
def set_default_authentication_realm(realm):
global _default_realm
_default_realm = realm
@elasticapm.capture_span()
def publish(request, module_name, after_list, debug=0,
# Optimize:
call_object=call_object,
missing_name=missing_name,
dont_publish_class=dont_publish_class,
mapply=mapply,
):
(bobo_before, bobo_after, object, realm, debug_mode, err_hook,
validated_hook, transactions_manager) = get_module_info(module_name)
parents = None
response = None
#client.begin_transaction('request_mapply')
try:
notify(pubevents.PubStart(request))
# TODO pass request here once BaseRequest implements IParticipation
newInteraction()
request.processInputs()
request_get = request.get
response = request.response
# First check for "cancel" redirect:
if request_get('SUBMIT', '').strip().lower() == 'cancel':
cancel = request_get('CANCEL_ACTION', '')
if cancel:
# Relative URLs aren't part of the spec, but are accepted by
# some browsers.
for part, base in zip(urlparse(cancel)[:3],
urlparse(request['BASE1'])[:3]):
if not part:
continue
if not part.startswith(base):
cancel = ''
break
if cancel:
raise Redirect(cancel)
after_list[0] = bobo_after
if debug_mode:
response.debug_mode = debug_mode
if realm and not request.get('REMOTE_USER', None):
response.realm = realm
noSecurityManager()
if bobo_before is not None:
bobo_before()
# Get the path list.
# According to RFC1738 a trailing space in the path is valid.
path = request_get('PATH_INFO')
request['PARENTS'] = parents = [object]
if transactions_manager:
transactions_manager.begin()
object = request.traverse(path, validated_hook=validated_hook)
if IBrowserPage.providedBy(object):
request.postProcessInputs()
notify(pubevents.PubAfterTraversal(request))
if transactions_manager:
recordMetaData(object, request)
#Elastic Code - Client txn starts
client.begin_transaction('request_mapply')
result = mapply(object, request.args, request,
call_object, 1,
missing_name,
dont_publish_class,
request, bind=1)
#import pdb; pdb.set_trace()
#Elastic Code - Client txn ends
client.end_transaction(request.method + " " + request.get('PATH_INFO'), response.status)
if result is not response:
response.setBody(result)
notify(pubevents.PubBeforeCommit(request))
client.end_transaction(request.method + " " + request.get('PATH_INFO'), response.status)
if transactions_manager:
transactions_manager.commit()
notify(pubevents.PubSuccess(request))
endInteraction()
#client.end_transaction(request.method + " " + request.get('PATH_INFO'), response.status)
return response
except:
# save in order to give 'PubFailure' the original exception info
exc_info = sys.exc_info()
# DM: provide nicer error message for FTP
sm = None
if response is not None:
sm = getattr(response, "setMessage", None)
if sm is not None:
from asyncore import compact_traceback
cl, val = sys.exc_info()[:2]
sm('%s: %s %s' % (
getattr(cl, '__name__', cl), val,
debug_mode and compact_traceback()[-1] or ''))
# debug is just used by tests (has nothing to do with debug_mode!)
if not debug and err_hook is not None:
retry = False
if parents:
parents = parents[0]
try:
try:
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
except Retry:
if not request.supports_retry():
return err_hook(parents, request,
sys.exc_info()[0],
sys.exc_info()[1],
sys.exc_info()[2],
)
retry = True
finally:
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try:
try:
notify(pubevents.PubBeforeAbort(
request, exc_info, retry))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(pubevents.PubFailure(request, exc_info, retry))
# Only reachable if Retry is raised and request supports retry.
newrequest = request.retry()
request.close() # Free resources held by the request.
# Set the default layer/skin on the newly generated request
if ISkinnable.providedBy(newrequest):
setDefaultSkin(newrequest)
try:
return publish(newrequest, module_name, after_list, debug)
finally:
newrequest.close()
else:
# Note: 'abort's can fail.
# Nevertheless, we want end request handling.
try:
try:
notify(pubevents.PubBeforeAbort(request, exc_info, False))
finally:
if transactions_manager:
transactions_manager.abort()
finally:
endInteraction()
notify(pubevents.PubFailure(request, exc_info, False))
raise
#@elasticapm.capture_span()
def publish_module_standard(
module_name,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
environ=os.environ, debug=0, request=None, response=None):
#client.begin_transaction('request')
must_die = 0
status = 200
after_list = [None]
try:
try:
if response is None:
response = Response(stdout=stdout, stderr=stderr)
else:
stdout = response.stdout
# debug is just used by tests (has nothing to do with debug_mode!)
response.handle_errors = not debug
if request is None:
request = Request(stdin, environ, response)
setRequest(request)
# make sure that the request we hand over has the
# default layer/skin set on it; subsequent code that
# wants to look up views will likely depend on it
if ISkinnable.providedBy(request):
setDefaultSkin(request)
#traceparent_string = elasticapm.get_trace_parent_header()
#parent = elasticapm.trace_parent_from_headers(traceparent_string)
#with elasticapm.capture_span('jiva_span', labels={"type": "jiva_publish"}):
#client.begin_transaction('request')
#client.begin_transaction(transaction_type="request", trace_parent=parent)
response = publish(request, module_name, after_list, debug=debug)
#import pdb; pdb.set_trace()
#elasticapm.set_context(lambda: get_data_from_request(request), "request")
#elasticapm.set_context(lambda: get_data_from_response(response), "response")
#client.end_transaction(request.method + " " + request.get('PATH_INFO'), response.status)
except (SystemExit, ImportError):
# XXX: Rendered ImportErrors were never caught here because they
# were re-raised as string exceptions. Maybe we should handle
# ImportErrors like all other exceptions. Currently they are not
# re-raised at all, so they don't show up here.
must_die = sys.exc_info()
request.response.exception(1)
except:
# debug is just used by tests (has nothing to do with debug_mode!)
if debug:
raise
request.response.exception()
status = response.getStatus()
if response:
outputBody = getattr(response, 'outputBody', None)
if outputBody is not None:
outputBody()
else:
response = str(response)
if response:
stdout.write(response)
# The module defined a post-access function, call it
if after_list[0] is not None:
after_list[0]()
finally:
if request is not None:
request.close()
clearRequest()
if must_die:
# Try to turn exception value into an exit code.
try:
if hasattr(must_die[1], 'code'):
code = must_die[1].code
else:
code = int(must_die[1])
except:
code = must_die[1] and 1 or 0
if hasattr(request.response, '_requestShutdown'):
request.response._requestShutdown(code)
try:
reraise(must_die[0], must_die[1], must_die[2])
finally:
must_die = None
return status
_l = allocate_lock()
#@elasticapm.capture_span()
def get_module_info(module_name, modules={},
acquire=_l.acquire,
release=_l.release):
if module_name in modules:
return modules[module_name]
if module_name[-4:] == '.cgi':
module_name = module_name[:-4]
acquire()
tb = None
g = globals()
try:
try:
module = __import__(module_name, g, g, ('__doc__',))
# Let the app specify a realm
if hasattr(module, '__bobo_realm__'):
realm = module.__bobo_realm__
elif _default_realm is not None:
realm = _default_realm
else:
realm = module_name
# Check for debug mode
if hasattr(module, '__bobo_debug_mode__'):
debug_mode = bool(module.__bobo_debug_mode__)
else:
debug_mode = _default_debug_mode
bobo_before = getattr(module, "__bobo_before__", None)
bobo_after = getattr(module, "__bobo_after__", None)
if hasattr(module, 'bobo_application'):
object = module.bobo_application
elif hasattr(module, 'web_objects'):
object = module.web_objects
else:
object = module
error_hook = getattr(module, 'zpublisher_exception_hook', None)
validated_hook = getattr(
module, 'zpublisher_validated_hook', validate_user)
transactions_manager = getattr(
module, 'zpublisher_transactions_manager', None)
if not transactions_manager:
# Create a default transactions manager for use
# by software that uses ZPublisher and ZODB but
# not the rest of Zope.
transactions_manager = DefaultTransactionsManager()
info = (bobo_before, bobo_after, object, realm, debug_mode,
error_hook, validated_hook, transactions_manager)
modules[module_name] = modules[module_name + '.cgi'] = info
return info
except Exception:
t, v, tb = sys.exc_info()
reraise(t, str(v), tb)
finally:
tb = None
release()
class DefaultTransactionsManager(object):
def begin(self):
transaction.begin()
def commit(self):
if transaction.isDoomed():
transaction.abort()
else:
transaction.commit()
def abort(self):
transaction.abort()
def publish_module(module_name,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
environ=os.environ, debug=0, request=None, response=None):
""" publish a Python module """
return publish_module_standard(module_name, stdin, stdout, stderr,
environ, debug, request, response)