Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
haotianw465 committed Oct 10, 2017
1 parent 1a5fab2 commit a00b8b5
Show file tree
Hide file tree
Showing 120 changed files with 6,459 additions and 2 deletions.
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.DS_Store
*.pyc
.Python
.cache

build
bin
include
lib
dist
*.egg
*.egg-info
.tox
.python-version

pip-selfcheck.json

.coverage*
htmlcov
26 changes: 26 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
=========
CHANGELOG
=========

0.93
====
* The X-Ray SDK for Python is now an open source project. You can follow the project and submit issues and pull requests on GitHub: https://github.com/aws/aws-xray-sdk-python

0.92.2
======
* bugfix: Fixed an issue that caused the X-Ray recorder to omit the origin when recording segments with a service plugin. This caused the service's type to not appear on the service map in the X-Ray console.

0.92.1
======
* bugfix: Fixed an issue that caused all calls to Amazon DynamoDB tables to be grouped under a single node in the service map. With this update, each table gets a separate node.

0.92
====

* feature: Add Flask support
* feature: Add dynamic naming on segment name

0.91.1
======

* bugfix: The SDK has been released as a universal wheel
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include aws_xray_sdk/ext/botocore/*.json
include aws_xray_sdk/core/sampling/*.json
include README.md
include LICENSE
156 changes: 154 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,154 @@
# aws-xray-sdk-python
AWS X-Ray SDK for the Python programming language
# AWS X-Ray SDK for Python <sup><sup><sup>(beta)</sup></sup></sup>

![Screenshot of the AWS X-Ray console](/images/example_servicemap.png?raw=true)

## Installing

The AWS X-Ray SDK for Python is compatible with Python 2.7, 3.4, 3.5, and 3.6.

Install the SDK using the following command (the SDK's non-testing dependencies will be installed).

```
pip install aws-xray-sdk
```

To install the SDK's testing dependencies, use the following command.

```
pip install tox
```

## Getting Help

Use the following community resources for getting help with the SDK. We use the GitHub
issues for tracking bugs and feature requests.

* Ask a question in the [AWS X-Ray Forum](https://forums.aws.amazon.com/forum.jspa?forumID=241&start=0).
* Open a support ticket with [AWS Support](http://docs.aws.amazon.com/awssupport/latest/user/getting-started.html).
* If you think you may have found a bug, open an [issue](https://github.com/aws/aws-xray-sdk-python/issues/new).

## Opening Issues

If you encounter a bug with the AWS X-Ray SDK for Python, we want to hear about
it. Before opening a new issue, search the [existing issues](https://github.com/aws/aws-xray-sdk-python/issues)
to see if others are also experiencing the issue. Include the version of the AWS X-Ray
SDK for Python, Python language, and botocore/boto3 if applicable. In addition,
include the repro case when appropriate.

The GitHub issues are intended for bug reports and feature requests. For help and
questions about using the AWS SDK for Python, use the resources listed
in the [Getting Help](https://github.com/aws/aws-xray-sdk-python#getting-help) section. Keeping the list of open issues lean helps us respond in a timely manner.

## Documentation

The [developer guide](https://docs.aws.amazon.com/xray/latest/devguide) provides in-depth
guidance about using the AWS X-Ray service.
The [API Reference](http://docs.aws.amazon.com/xray-sdk-for-python/latest/reference/)
provides guidance for using the SDK and module-level documentation.

## Quick Start

**Configuration**

```python
from aws_xray_sdk.core import xray_recorder

xray_recorder.configure(
sampling=False,
context_missing='LOG_ERROR',
plugins=('EC2Plugin', 'ECSPlugin', 'ElasticBeanstalkPlugin'),
daemon_address='127.0.0.1:3000',
dynamic_naming='*mysite.com*'
)
```

**Start a custom segment/subsegment**

```python
from aws_xray_sdk.core import xray_recorder

# Start a segment
segment = xray_recorder.begin_segment('segment_name')
# Start a subsegment
subsegment = xray_recorder.begin_subsegment('subsegment_name')

# Add metadata or annotation here if necessary
segment.put_metadata('key', dict, 'namespace')
subsegment.put_annotation('key', 'value')
xray_recorder.end_subsegment()

# Close the segment
xray_recorder.end_segment()
```

**Capture**

```python
from aws_xray_sdk.core import xray_recorder

@xray_recorder.capture('subsegment_name')
def myfunc():
# Do something here

myfunc()
```

**Trace AWS Lambda functions**

```python
from aws_xray_sdk.core import xray_recorder

def lambda_handler(event, context):
# ... some code

subsegment = xray_recorder.begin_subsegment('subsegment_name')
# Code to record
# Add metadata or annotation here, if necessary
subsegment.put_metadata('key', dict, 'namespace')
subsegment.put_annotation('key', 'value')

xray_recorder.end_subsegment()

# ... some other code
```

**Patch third-party libraries**

```python
from aws_xray_sdk.core import patch

libs_to_patch = ('boto3', 'mysql', 'requests')
patch(libs_to_patch)
```

**Add Django middleware**

In django settings.py, use the following.

```python
INSTALLED_APPS = [
# ... other apps
'aws_xray_sdk.ext.django',
]

MIDDLEWARE = [
'aws_xray_sdk.ext.django.middleware.XRayMiddleware',
# ... other middlewares
]
```

**Add Flask middleware**

```python
from aws_xray_sdk.core import xray_recorder
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware

app = Flask(__name__)

xray_recorder.configure(service='fallback_name', dynamic_naming='*mysite.com*')
XRayMiddleware(app, xray_recorder)
```

## License

The AWS X-Ray SDK for Python is licensed under the Apache 2.0 License. See LICENSE and NOTICE.txt for more information.
Empty file added __init__.py
Empty file.
Empty file added aws_xray_sdk/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions aws_xray_sdk/core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .recorder import AWSXRayRecorder
from .patcher import patch_all, patch


xray_recorder = AWSXRayRecorder()

__all__ = [
'patch',
'patch_all',
'xray_recorder',
'AWSXRayRecorder',
]
136 changes: 136 additions & 0 deletions aws_xray_sdk/core/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import threading
import logging
import os

from .exceptions.exceptions import SegmentNotFoundException

log = logging.getLogger(__name__)

MISSING_SEGMENT_MSG = 'cannot find the current segment/subsegment, please make sure you have a segment open'
SUPPORTED_CONTEXT_MISSING = ('RUNTIME_ERROR', 'LOG_ERROR')
CXT_MISSING_STRATEGY_KEY = 'AWS_XRAY_CONTEXT_MISSING'


class Context(object):
"""
The context storage class to store trace entities(segments/subsegments).
The default implementation uses threadlocal to store these entities.
It also provides interfaces to manually inject trace entities which will
replace the current stored entities and to clean up the storage.
For any data access or data mutation, if there is no active segment present
if will use user-defined behavior to handle such case. By default it throws
an runtime error.
This data structure is thread-safe.
"""
def __init__(self, context_missing='RUNTIME_ERROR'):

self._local = threading.local()
strategy = os.getenv(CXT_MISSING_STRATEGY_KEY, context_missing)
self._context_missing = strategy

def put_segment(self, segment):
"""
Store the segment created by ``xray_recorder`` to the context.
It overrides the current segment if there is already one.
"""
setattr(self._local, 'entities', [segment])

def end_segment(self, end_time=None):
"""
End the current active segment.
:param int end_time: epoch in seconds. If not specified the current
system time will be used.
"""
entity = self.get_trace_entity()
if not entity:
log.warning("No segment to end")
return
if self._is_subsegment(entity):
entity.parent_segment.close(end_time)
else:
entity.close(end_time)

def put_subsegment(self, subsegment):
"""
Store the subsegment created by ``xray_recorder`` to the context.
If you put a new subsegment while there is already an open subsegment,
the new subsegment becomes the child of the existing subsegment.
"""
entity = self.get_trace_entity()
if not entity:
log.warning("Active segment or subsegment not found. Discarded %s." % subsegment.name)
return

entity.add_subsegment(subsegment)
self._local.entities.append(subsegment)

def end_subsegment(self, end_time=None):
"""
End the current active segment. Return False if there is no
subsegment to end.
:param int end_time: epoch in seconds. If not specified the current
system time will be used.
"""
subsegment = self.get_trace_entity()
if self._is_subsegment(subsegment):
subsegment.close(end_time)
self._local.entities.pop()
return True
else:
log.warning("No subsegment to end.")
return False

def get_trace_entity(self):
"""
Return the current trace entity(segment/subsegment). If there is none,
it behaves based on pre-defined ``context_missing`` strategy.
"""
if not getattr(self._local, 'entities', None):
return self.handle_context_missing()

return self._local.entities[-1]

def set_trace_entity(self, trace_entity):
"""
Store the input trace_entity to local context. It will overwrite all
existing ones if there is any.
"""
setattr(self._local, 'entities', [trace_entity])

def clear_trace_entities(self):
"""
clear all trace_entities stored in the local context.
In case of using threadlocal to store trace entites, it will
clean up all trace entities created by the current thread.
"""
self._local.__dict__.clear()

def handle_context_missing(self):
"""
Called whenever there is no trace entity to access or mutate.
"""
if self.context_missing == 'RUNTIME_ERROR':
log.error(MISSING_SEGMENT_MSG)
raise SegmentNotFoundException(MISSING_SEGMENT_MSG)
else:
log.error(MISSING_SEGMENT_MSG)

def _is_subsegment(self, entity):

return hasattr(entity, 'type') and entity.type == 'subsegment'

@property
def context_missing(self):
return self._context_missing

@context_missing.setter
def context_missing(self, value):
if value not in SUPPORTED_CONTEXT_MISSING:
log.warning('specified context_missing not supported, using default.')
return

self._context_missing = value
Empty file.
Loading

0 comments on commit a00b8b5

Please sign in to comment.