File: boto_utils.py

package info (click to toggle)
python-aws-xray-sdk 0.95-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 792 kB
  • sloc: python: 3,006; makefile: 20
file content (129 lines) | stat: -rw-r--r-- 4,095 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
from __future__ import absolute_import
# Need absolute import as botocore is also in the current folder for py27
import json

from pkg_resources import resource_filename
from botocore.exceptions import ClientError

from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.core.models import http

from aws_xray_sdk.ext.util import inject_trace_header, to_snake_case


with open(resource_filename(__name__, 'resources/aws_para_whitelist.json'), 'r') as data_file:
    whitelist = json.load(data_file)


def inject_header(wrapped, instance, args, kwargs):
    headers = args[0]
    inject_trace_header(headers, xray_recorder.current_subsegment())
    return wrapped(*args, **kwargs)


def aws_meta_processor(wrapped, instance, args, kwargs,
                       return_value, exception, subsegment, stack):
    region = instance.meta.region_name

    if 'operation_name' in kwargs:
        operation_name = kwargs['operation_name']
    else:
        operation_name = args[0]

    aws_meta = {
        'operation': operation_name,
        'region': region,
    }

    if return_value:
        resp_meta = return_value.get('ResponseMetadata')
        if resp_meta:
            aws_meta['request_id'] = resp_meta.get('RequestId')
            subsegment.put_http_meta(http.STATUS,
                                     resp_meta.get('HTTPStatusCode'))
            # for service like S3 that returns special request id in response headers
            if 'HTTPHeaders' in resp_meta and resp_meta['HTTPHeaders'].get('x-amz-id-2'):
                aws_meta['id_2'] = resp_meta['HTTPHeaders']['x-amz-id-2']

    elif exception:
        _aws_error_handler(exception, stack, subsegment, aws_meta)

    _extract_whitelisted_params(subsegment.name, operation_name,
                                aws_meta, args, kwargs, return_value)

    subsegment.set_aws(aws_meta)


def _aws_error_handler(exception, stack, subsegment, aws_meta):

    if not exception or not isinstance(exception, ClientError):
        return

    response_metadata = exception.response.get('ResponseMetadata')

    if not response_metadata:
        return

    aws_meta['request_id'] = response_metadata.get('RequestId')

    status_code = response_metadata.get('HTTPStatusCode')

    subsegment.put_http_meta(http.STATUS, status_code)
    subsegment.add_exception(exception, stack, True)


def _extract_whitelisted_params(service, operation,
                                aws_meta, args, kwargs, response):

    # check if service is whitelisted
    if service not in whitelist['services']:
        return
    operations = whitelist['services'][service]['operations']

    # check if operation is whitelisted
    if operation not in operations:
        return
    params = operations[operation]

    # record whitelisted request/response parameters
    if 'request_parameters' in params:
        _record_params(params['request_parameters'], args[1], aws_meta)

    if 'request_descriptors' in params:
        _record_special_params(params['request_descriptors'],
                               args[1], aws_meta)

    if 'response_parameters' in params and response:
        _record_params(params['response_parameters'], response, aws_meta)

    if 'response_descriptors' in params and response:
        _record_special_params(params['response_descriptors'],
                               response, aws_meta)


def _record_params(whitelisted, actual, aws_meta):

    for key in whitelisted:
        if key in actual:
            snake_key = to_snake_case(key)
            aws_meta[snake_key] = actual[key]


def _record_special_params(whitelisted, actual, aws_meta):

    for key in whitelisted:
        if key in actual:
            _process_descriptor(whitelisted[key], actual[key], aws_meta)


def _process_descriptor(descriptor, value, aws_meta):

    # "get_count" = true
    if 'get_count' in descriptor and descriptor['get_count']:
        value = len(value)

    # "get_keys" = true
    if 'get_keys' in descriptor and descriptor['get_keys']:
        value = value.keys()

    aws_meta[descriptor['rename_to']] = value