Repository URL to install this package:
Version:
0.17.0 ▾
|
"""
Available HTTP Client for Datadog API client.
Priority:
1. `requests` 3p module
2. `urlfetch` 3p module - Google App Engine only
"""
# stdlib
import logging
import urllib
# 3p
try:
import requests
except ImportError:
requests = None
try:
from google.appengine.api import urlfetch, urlfetch_errors
except ImportError:
urlfetch, urlfetch_errors = None, None
# datadog
from datadog.api.exceptions import ClientError, HTTPError, HttpTimeout
log = logging.getLogger('datadog.api')
class HTTPClient(object):
"""
An abstract generic HTTP client. Subclasses must implement the `request` methods.
"""
@classmethod
def request(cls, method, url, headers, params, data, timeout, proxies, verify, max_retries):
"""
Main method to be implemented by HTTP clients.
The returned data structure has the following fields:
* `content`: string containing the response from the server
* `status_code`: HTTP status code returned by the server
Can raise the following exceptions:
* `ClientError`: server cannot be contacted
* `HttpTimeout`: connection timed out
* `HTTPError`: unexpected HTTP response code
"""
raise NotImplementedError(
u"Must be implemented by HTTPClient subclasses."
)
class RequestClient(HTTPClient):
"""
HTTP client based on 3rd party `requests` module.
"""
@classmethod
def request(cls, method, url, headers, params, data, timeout, proxies, verify, max_retries):
"""
"""
# Use a session to set a max_retries parameters
s = requests.Session()
http_adapter = requests.adapters.HTTPAdapter(max_retries=max_retries)
s.mount('https://', http_adapter)
try:
result = s.request(
method, url,
headers=headers, params=params, data=data,
timeout=timeout,
proxies=proxies, verify=verify)
result.raise_for_status()
except requests.ConnectionError as e:
raise ClientError(method, url, e)
except requests.exceptions.Timeout:
raise HttpTimeout(method, url, timeout)
except requests.exceptions.HTTPError as e:
if e.response.status_code in (400, 403, 404, 409):
# This gets caught afterwards and raises an ApiError exception
pass
else:
raise HTTPError(e.response.status_code, result.reason)
except TypeError as e:
raise TypeError(
u"Your installed version of `requests` library seems not compatible with"
u"Datadog's usage. We recommand upgrading it ('pip install -U requests')."
u"If you need help or have any question, please contact support@datadoghq.com"
)
return result
class URLFetchClient(HTTPClient):
"""
HTTP client based on Google App Engine `urlfetch` module.
"""
@classmethod
def request(cls, method, url, headers, params, data, timeout, proxies, verify, max_retries):
"""
Wrapper around `urlfetch.fetch` method.
TO IMPLEMENT:
* `max_retries`
"""
# No local certificate file can be used on Google App Engine
validate_certificate = True if verify else False
# Encode parameters in the url
url_with_params = "{url}?{params}".format(
url=url,
params=urllib.urlencode(params)
)
try:
result = urlfetch.fetch(
url=url_with_params,
method=method,
headers=headers,
validate_certificate=validate_certificate,
deadline=timeout,
payload=data,
# setting follow_redirects=False may be slightly faster:
# https://cloud.google.com/appengine/docs/python/microservice-performance#use_the_shortest_route
follow_redirects=False
)
cls.raise_on_status(result)
except urlfetch.DownloadError as e:
raise ClientError(method, url, e)
except urlfetch_errors.DeadlineExceededError:
raise HttpTimeout(method, url, timeout)
return result
@classmethod
def raise_on_status(cls, result):
"""
Raise on HTTP status code errors.
"""
status_code = result.status_code
if (status_code / 100) != 2:
if status_code in (400, 403, 404, 409):
pass
else:
raise HTTPError(status_code)
def resolve_http_client():
"""
Resolve an appropriate HTTP client based the defined priority and user environment.
"""
if requests:
log.debug(u"Use `requests` based HTTP client.")
return RequestClient
if urlfetch and urlfetch_errors:
log.debug(u"Use `urlfetch` based HTTP client.")
return URLFetchClient
raise ImportError(
u"Datadog API client was unable to resolve a HTTP client. "
u" Please install `requests` library."
)