"""Application Handlers. Requests are redirected to handlers, which are responsible for getting information from the URL and passing it down to the logic layer. The way each layer talks to each other is through Response objects which defines the type status of the data and the data itself. Please note: the Orchard uses the term handlers over views as convention for clarity See: oto.response for more details. """ import boto3 from flask import g from flask import jsonify from flask import request from oto import response from oto.adaptors.flask import flaskify from cloudwatch_logs import config from cloudwatch_logs.api import app from cloudwatch_logs.logic import hello from cloudwatch_logs.logic import logs @app.route('/', methods=['GET']) def hello_world(): """Hello World with an optional GET param "name".""" name = request.args.get('name', '') return flaskify(hello.say_hello(name)) @app.route('/', methods=['GET']) def hello_world_username(username): """Hello World on /. Args: username (str): the user's username. """ return flaskify(hello.say_hello(username)) @app.route(config.HEALTH_CHECK, methods=['GET']) def health(): """Check the health of the application.""" return jsonify({'status': 'ok'}) @app.route('/cloudwatch/log-stream', methods=['POST']) def create_cw_log_stream(): """Create a new log stream for an existing group on aws cloudwatch logs. A log stream is a sequence of log events that share the same source. Returns: flask.Response: containing user metadata. """ data = request.get_json() group_name = data.get('group_name', None) stream_name = data.get('stream_name', None) if not group_name or not stream_name: return flaskify(response.create_fatal_response('Invalid request.')) client = boto3.client('logs') stream_response = client.create_log_stream( logGroupName=group_name, logStreamName=stream_name ) return flaskify(response.Response(stream_response)) @app.errorhandler(500) def exception_handler(error): """Handle error when uncaught exception is raised. Default exception handler. Note: Exception will also be sent to Sentry if config.SENTRY is set. Returns: flask.Response: A 500 response with JSON 'code' & 'message' payload. """ message = ( 'The server encountered an internal error ' 'and was unable to complete your request.') g.log.exception(error) return flaskify(response.create_fatal_response(message)) @app.route('/twilio/logs', methods=['POST']) def add_twilio_logs_to_cw(): """Add twilio logs to aws cloudwatch. This endpoint will get a POST callback from twilio, so validations are not useful. Returns: flask.Response: containing user metadata. """ data = request.form.to_dict(flat=False) sequence_token = logs.get_next_token( config.TWILIO_LOG_GROUP, config.TWILIO_LOG_STREAM) result = logs.write_cloudwatch_log( data, sequence_token, config.TWILIO_LOG_GROUP, config.TWILIO_LOG_STREAM) return flaskify(result) @app.route('/twilio/datadog/logs', methods=['POST']) def add_twilio_logs_to_datadog(): """Add twilio logs to datadog. This endpoint will get a POST callback from twilio, so validations are not useful. Returns: flask.Response: containing user metadata. """ data = request.form.to_dict(flat=False) return flaskify(logs.write_datadog_log(data))