.. _configurations:

Configure Global Recorder
=========================

Sampling
--------
Sampling is enabled by default.
Whenever the global recorder creates a segment,
it decides whether to sample this segment.
If it does not sample this segment, it is discarded and not sent to the
X-Ray daemon.

To turn off sampling, use code like the following::

    from aws_xray_sdk.core import xray_recorder
    xray_recorder.configure(sampling=False)

You can also configure the sampling rules::

    xray_recorder.configure(sampling_rules=your_rules)

The input can either be an absolute path to your sampling rule
*.json* file or a dictionary.

The following code is an example of a rule configuration::

    {
    "version": 1,
    "rules": [
        {
        "description": "Player moves.",
        "service_name": "*",
        "http_method": "*",
        "url_path": "/api/move/*",
        "fixed_target": 0,
        "rate": 0.05
        }
    ],
    "default": {
        "fixed_target": 1,
        "rate": 0.1
        }
    }

This example defines one custom rule and a default rule.
The custom rule applies a five-percent sampling rate
with no minimum number of requests to trace for paths under */api/move/*.
The default rule traces the first request each second and 10 percent of
additional requests.
The SDK applies custom rules in the order in which they are defined.
If a request matches multiple custom rules, the SDK applies only the first rule.
You can use wildcard character "*" and "?" in service_name, http_method and
url_path.
"*" represents any combination of characters. "?" represents a single character.

Note that sampling configurations have no effect if the application runs in AWS Lambda.

Plugins
-------
The plugin adds extra metadata for each segment if the app is running on that environment.
The SDK provides three plugins:

* Amazon EC2 – EC2Plugin adds the instance ID and Availability Zone.
* Elastic Beanstalk – ElasticBeanstalkPlugin adds the environment name, version label, and deployment ID.
* Amazon ECS – ECSPlugin adds the container host name

To use plugins, use code like the following::

    # a tuple of strings
    plugins = ('elasticbeanstalk_plugin', 'ec2_plugin', 'ecs_plugin')
    # alternatively you can use 
    plugins = ('ElasticBeanstalkPlugin', 'EC2Plugin', 'ECSPlugin')

    xray_recorder.configure(plugins=plugins)

Order matters in the tuple and the origin of the segment is set from the last plugin.
Therefore, in the previous example, if the program runs on ECS, the segment origin is
'AWS::ECS::CONTAINER'.
Plugins must be configured before patching any third party libraries to
avoid unexpected behavior.
Plugins are employed after they are specified.

Context Missing Strategy
------------------------
Defines the recorder behavior when your instrumented code attempts to record data when no segment is open.
Configure like the following::

    xray_recorder.configure(context_missing='Your Strategy Name Here')

Supported strategies are:

* RUNTIME_ERROR: throw an SegmentNotFoundException
* LOG_ERROR: log an error and continue

Segment Dynamic Naming
----------------------
For a web application you might want to name the segment using host names. You can pass in a pattern
with wildcard character "*" and "?". "*" represents any combination of characters.
"?" represents a single character. If the host name from incoming request's header matches the pattern,
the host name will be used as the segment name, otherwise it uses fallback name defined in ``AWS_XRAY_TRACING_NAME``.
To configure dynamic naming, use code like the following::
    
    xray_recorder.configure(dynamic_naming='*.example.com')

Environment Variables
---------------------
There are three supported environment variables to configure the global
recorder:

* AWS_XRAY_CONTEXT_MISSING: configure context missing strategy
* AWS_XRAY_TRACING_NAME: default segment name
* AWS_XRAY_DAEMON_ADDRESS: where the recorder sends data to over UDP

Environment variables has higher precedence over ``xray_recorder.configure()``

Logging
-------
The SDK uses Python's built-in ``logging`` module to perform logging.
You can configure the SDK logging just like how you configure other
python libraries. An example of set the SDK log level is like the following::

    logging.basicConfig(level='DEBUG')
    logging.getLogger('aws_xray_sdk').setLevel(logging.WARNING)

Context Storage
---------------
The global recorder uses threadlocal to store active segments/subsegments.
You can override the default context class to implement your own context storage::
    
    from aws_xray_sdk.core.context import Context

    class MyOwnContext(Context):

        def put_segment(self, segment):
        # store the segment created by ``xray_recorder`` to the context.
        pass

        def end_segment(self, end_time=None):
        # end the segment in the current context.
        pass

        def put_subsegment(self, subsegment):
        # store the subsegment created by ``xray_recorder`` to the context.
        pass

        def end_subsegment(self, end_time=None):
        # end the subsegment in the current context.
        pass

        def get_trace_entity(self):
        # get the current active trace entity(segment or subsegment).
        pass

        def set_trace_entity(self, trace_entity):
        # manually inject a trace entity to the context storage.
        pass

        def clear_trace_entities(self):
        # clean up context storage.
        pass

        def handle_context_missing(self):
        # behavior on no trace entity to access or mutate.
        pass

The function ``current_segment`` and ``current_subsegment`` on recorder level uses
``context.get_trace_entity()`` and dynamically return the expected type by using internal
references inside segment/subsegment objects.

Then you can pass your own context::

    my_context=MyOwnContext()
    xray_recorder.configure(context=my_context)

Emitter
-------
The default emitter uses non-blocking socket to send data to the X-Ray daemon.
It doesn't retry on IOError. To override the default emitter::

    from aws_xray_sdk.core.emitters.udp_emitter import UDPEmitter

    class MyOwnEmitter(UDPEmitter):

        def send_entity(self, entity):
        # send the input segment/subsegment to the X-Ray daemon.
        # Return True on success and False on failure.
        pass

        def set_daemon_address(self, address):
        # parse input full address like 127.0.0.1:8000 to ip and port and
        # store them to the local emitter properties.
        pass

Then you can pass your own emitter::

    my_emitter = MyOwnEmitter()
    xray_recorder.configure(emitter=my_emitter)
