blob: d875dee396015301dd416a56672fee92ebba58cc [file]
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import time
import webapp2
from infra_libs.ts_mon import exporter
from infra_libs.ts_mon import handlers
from infra_libs.ts_mon import shared
from infra_libs.ts_mon.common import http_metrics
from infra_libs.ts_mon.common import interface
def instrument(app, time_fn=time.time):
"""Instruments an webapp2 WSGI application."""
if _is_instrumented(app):
return
old_dispatcher = app.router.dispatch
def dispatch(_, request, response):
return _instrumented_dispatcher(
old_dispatcher, request, response, time_fn=time_fn)
app.router.set_dispatcher(dispatch)
app.router.__instrumented_by_ts_mon = True
def _is_instrumented(app):
"""Checks if tsmon dispatcher has been installed into the app."""
return hasattr(app.router, '__instrumented_by_ts_mon')
def _instrumented_dispatcher(dispatcher, request, response, time_fn=time.time):
start_time = time_fn()
response_status = 0
time_now = time_fn()
try:
with exporter.parallel_flush(time_now):
ret = dispatcher(request, response)
except webapp2.HTTPException as ex:
response_status = ex.code
raise
except Exception:
response_status = 500
raise
else:
if isinstance(ret, webapp2.Response):
response = ret
response_status = response.status_int
finally:
elapsed_ms = int((time_fn() - start_time) * 1000)
# Use the route template regex, not the request path, to prevent an
# explosion in possible field values.
name = request.route.template if request.route is not None else ''
http_metrics.update_http_server_metrics(
name,
response_status,
elapsed_ms,
request_size=request.content_length,
response_size=response.content_length,
user_agent=request.user_agent)
return ret
class TaskNumAssignerHandler(webapp2.RequestHandler):
@handlers.report_memory
def get(self):
if self.request.headers.get('X-Appengine-Cron') != 'true':
self.abort(403)
with shared.instance_namespace_context():
handlers._assign_task_num()
interface.invoke_global_callbacks()
def create_app():
return webapp2.WSGIApplication([
(r'/internal/cron/ts_mon/send', TaskNumAssignerHandler),
])
tasknum_assigner = create_app()