Skip to content

Commit

Permalink
turned servers list setting into single server string setting (#59)
Browse files Browse the repository at this point in the history
Also removed logic that would send events to multiple servers
  • Loading branch information
beniwohli authored and ruflin committed Sep 26, 2017
1 parent 81f6374 commit bf369ab
Show file tree
Hide file tree
Showing 14 changed files with 66 additions and 72 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
@@ -1,5 +1,11 @@
# Changelog

### master branch

* added request context information for Flask (#58)
* BREAKING: changed the `SERVERS` list setting to a single `SERVER` string setting.
With this change, we now only support sending events to a single server (#59)

### 1.0.0.dev1

* unified configuration across supported frameworks (#33)
Expand Down
17 changes: 7 additions & 10 deletions docs/configuration.asciidoc
Expand Up @@ -58,21 +58,18 @@ In less regexy terms:
Your app name must only contain characters from the ASCII alphabet, numbers, dashes, underscores and spaces.

[float]
[[config-servers]]
==== `servers`
[[config-server]]
==== `server`

[options="header"]
|============
| Environment | Django/Flask | Default
| `ELASTIC_APM_SERVERS` | `SERVERS` | `['http://localhost:8200']`
| multiple values separated by commas, without spaces |||
| `ELASTIC_APM_SERVER` | `SERVER` | `'http://localhost:8200'`
|============

A list of URLs for your APM Servers.
The URL for your APM Server.
The URL must be fully qualified, including protocol (`http` or `https`) and port.

NOTE: if you configure multiple servers, errors and transactions are sent to each server.


[float]
[[config-transport-class]]
Expand Down Expand Up @@ -105,16 +102,16 @@ Note however that this can have adverse effects on performance.
| `ELASTIC_APM_SECRET_TOKEN` | `SECRET_TOKEN` | `None` | A random string
|============

This string is used to ensure that only your agents can send data to your APM servers.
Both the agents and the APM servers have to be configured with the same secret token.
This string is used to ensure that only your agents can send data to your APM server.
Both the agents and the APM server have to be configured with the same secret token.
One example to generate a secure secret token is:

[source,bash]
----
python -c "import uuid; print(str(uuid.uuid4()))"
----

WARNING: secret tokens only provide any security if your APM servers use TLS.
WARNING: secret tokens only provide any security if your APM server use TLS.

[float]
[[config-app-version]]
Expand Down
2 changes: 1 addition & 1 deletion docs/django.asciidoc
Expand Up @@ -280,7 +280,7 @@ Trying to send a test error using these settings:
APP_NAME: <APP_NAME>
SECRET_TOKEN: <SECRET_TOKEN>
SERVERS: http://localhost:8200
SERVER: http://localhost:8200
Success! We tracked the error successfully! You should be able to see it in a few seconds.
----
Expand Down
42 changes: 18 additions & 24 deletions elasticapm/base.py
Expand Up @@ -279,8 +279,8 @@ def capture(self, event_type, data=None, date=None,
data = self.build_msg_for_logging(event_type, data, date, extra, stack, **kwargs)

if data:
servers = [server + defaults.ERROR_API_PATH for server in self.config.servers]
self.send(servers=servers, **data)
server = self.config.server + defaults.ERROR_API_PATH
self.send(server=server, **data)
return data['errors'][0]['id']

def _send_remote(self, url, data, headers=None):
Expand Down Expand Up @@ -353,8 +353,7 @@ def send_remote(self, url, data, headers=None):
except Exception as e:
self.handle_transport_fail(exception=e)

def send(self, secret_token=None, auth_header=None,
servers=None, **data):
def send(self, secret_token=None, auth_header=None, server=None, **data):
"""
Serializes the message and passes the payload onto ``send_encoded``.
"""
Expand All @@ -364,38 +363,33 @@ def send(self, secret_token=None, auth_header=None,

message = self.encode(data)

return self.send_encoded(message,
secret_token=secret_token,
auth_header=auth_header,
servers=servers)
return self.send_encoded(message, secret_token=secret_token, auth_header=auth_header, server=server)

def send_encoded(self, message, secret_token, auth_header=None,
servers=None, **kwargs):
def send_encoded(self, message, secret_token, auth_header=None, server=None, **kwargs):
"""
Given an already serialized message, signs the message and passes the
payload off to ``send_remote`` for each server specified in the servers
payload off to ``send_remote`` for each server specified in the server
configuration.
"""
servers = servers or self.config.servers
if not servers:
warnings.warn('elasticapm client has no remote servers configured')
server = server or self.config.server
if not server:
warnings.warn('elasticapm client has no remote server configured')
return

if not auth_header:
if not secret_token:
secret_token = self.config.secret_token

auth_header = "Bearer %s" % (secret_token)
auth_header = "Bearer %s" % secret_token

for url in servers:
headers = {
'Authorization': auth_header,
'Content-Type': 'application/json',
'Content-Encoding': 'deflate',
'User-Agent': 'elasticapm-python/%s' % elasticapm.VERSION,
}
headers = {
'Authorization': auth_header,
'Content-Type': 'application/json',
'Content-Encoding': 'deflate',
'User-Agent': 'elasticapm-python/%s' % elasticapm.VERSION,
}

self.send_remote(url=url, data=message, headers=headers)
self.send_remote(url=server, data=message, headers=headers)

def encode(self, data):
"""
Expand Down Expand Up @@ -500,7 +494,7 @@ def _traces_collect(self):
})
api_path = defaults.TRANSACTIONS_API_PATH

self.send(servers=[server + api_path for server in self.config.servers], **data)
self.send(server=self.config.server + api_path, **data)

def get_app_info(self):
language_version = platform.python_version()
Expand Down
2 changes: 1 addition & 1 deletion elasticapm/conf/__init__.py
Expand Up @@ -135,7 +135,7 @@ class Config(_ConfigBase):
app_name = _ConfigValue('APP_NAME', validators=[lambda val: re.match('^[a-zA-Z0-9 _-]+$', val)], required=True)
secret_token = _ConfigValue('SECRET_TOKEN')
debug = _BoolConfigValue('DEBUG', default=False)
servers = _ListConfigValue('SERVERS', default=['http://localhost:8200'], required=True)
server = _ConfigValue('SERVER', default='http://localhost:8200', required=True)
include_paths = _ListConfigValue('INCLUDE_PATHS')
exclude_paths = _ListConfigValue('EXCLUDE_PATHS', default=['elasticapm'])
filter_exception_types = _ListConfigValue('FILTER_EXCEPTION_TYPES')
Expand Down
3 changes: 0 additions & 3 deletions elasticapm/conf/defaults.py
Expand Up @@ -20,9 +20,6 @@
# Allow local testing of ElasticAPM even if DEBUG is enabled
DEBUG = False

# This should be the schema+host of the APM Server server
SERVERS = ['http://localhost:8080']

# Error API path
ERROR_API_PATH = '/v1/errors'

Expand Down
8 changes: 4 additions & 4 deletions elasticapm/contrib/django/client.py
Expand Up @@ -226,13 +226,13 @@ def send(self, **kwargs):
"""
Serializes and signs ``data`` and passes the payload off to ``send_remote``
If ``servers`` was passed into the constructor, this will serialize the data and pipe it to
each server using ``send_remote()``.
If ``server`` was passed into the constructor, this will serialize the data and pipe it to
the server using ``send_remote()``.
"""
if self.config.servers:
if self.config.server:
return super(DjangoClient, self).send(**kwargs)
else:
self.error_logger.error('No servers configured, and elasticapm not installed. Cannot send message')
self.error_logger.error('No server configured, and elasticapm not installed. Cannot send message')
return None


Expand Down
4 changes: 2 additions & 2 deletions elasticapm/contrib/django/management/commands/elasticapm.py
Expand Up @@ -148,10 +148,10 @@ def handle_test(self, command, **options):
"Trying to send a test error to APM Server using these settings:\n\n"
"APP_NAME:\t\t\t%s\n"
"SECRET_TOKEN:\t\t%s\n"
"SERVERS:\t\t%s\n\n" % (
"SERVER:\t\t%s\n\n" % (
client.config.app_name,
client.config.secret_token,
', '.join(client.config.servers)
client.config.server,
)
)

Expand Down
2 changes: 1 addition & 1 deletion elasticapm/contrib/pylons/__init__.py
Expand Up @@ -22,7 +22,7 @@ def list_from_setting(config, setting):
class ElasticAPM(Middleware):
def __init__(self, app, config, client_cls=Client):
client = client_cls(
servers=list_from_setting(config, 'elasticapm.servers'),
server=config.get('elasticapm.server'),
timeout=config.get('elasticapm.timeout'),
name=config.get('elasticapm.name'),
app_name=config.get('elasticapm.app_name'),
Expand Down
6 changes: 3 additions & 3 deletions tests/asyncio/test_asyncio_client.py
Expand Up @@ -29,7 +29,7 @@ async def test_client_success():
from elasticapm.contrib.asyncio import Client

client = Client(
servers=['http://localhost'],
server='http://localhost',
app_name='app_name',
secret_token='secret',
transport_class='.'.join(
Expand All @@ -50,7 +50,7 @@ async def test_client_failure():
from elasticapm.transport.base import TransportException

client = Client(
servers=['http://error'],
server='http://error',
app_name='app_name',
secret_token='secret',
transport_class='.'.join(
Expand All @@ -70,7 +70,7 @@ async def test_client_failure_stdlib_exception(mocker):
from elasticapm.transport.base import TransportException

client = Client(
servers=['http://elastic.co'],
server='http://elastic.co',
app_name='app_name',
secret_token='secret',
async_mode=False,
Expand Down
30 changes: 15 additions & 15 deletions tests/client/client_tests.py
Expand Up @@ -102,7 +102,7 @@ def __repr__(self):
return repr(self.content)

client = Client(
servers=['localhost'],
server='localhost',
app_name=MyValue('bar'),
secret_token=MyValue('bay')
)
Expand All @@ -112,7 +112,7 @@ def __repr__(self):

def test_custom_transport():
client = Client(
servers=['localhost'],
server='localhost',
app_name='bar',
secret_token='baz',
transport_class='tests.client.client_tests.DummyTransport',
Expand All @@ -122,7 +122,7 @@ def test_custom_transport():

def test_empty_processor_list():
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
processors=[],
Expand All @@ -136,7 +136,7 @@ def test_send_remote_failover_sync(should_try, http_send):
should_try.return_value = True

client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
transport_class='elasticapm.transport.http_urllib3.Urllib3Transport',
Expand Down Expand Up @@ -165,7 +165,7 @@ def test_send_remote_failover_sync_stdlib(should_try, http_send):
should_try.return_value = True

client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
transport_class='elasticapm.transport.http_urllib3.Urllib3Transport',
Expand Down Expand Up @@ -193,7 +193,7 @@ def test_send_remote_failover_async(should_try, http_send):
should_try.return_value = True

client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
async_mode=True,
Expand Down Expand Up @@ -225,7 +225,7 @@ def test_send(time, send_remote):
public = "public"
access_token = "secret"
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
)
Expand All @@ -250,7 +250,7 @@ def test_send_not_enabled(time, send_remote):
time.return_value = 1328055286.51
with mock.patch.dict('os.environ', {'ELASTIC_APM_DISABLE_SEND': 'true'}):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
)
Expand All @@ -266,7 +266,7 @@ def test_send_not_enabled(time, send_remote):
def test_send_with_auth_header(time, send_remote):
time.return_value = 1328055286.51
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
)
Expand All @@ -290,7 +290,7 @@ def test_send_with_auth_header(time, send_remote):
@mock.patch('elasticapm.base.Client._traces_collect')
def test_client_shutdown_sync(mock_traces_collect, mock_close, mock_send):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
transport_class='elasticapm.transport.http_urllib3.Urllib3Transport',
Expand All @@ -307,7 +307,7 @@ def test_client_shutdown_sync(mock_traces_collect, mock_close, mock_send):
@mock.patch('elasticapm.base.Client._traces_collect')
def test_client_shutdown_async(mock_traces_collect, mock_send):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
async_mode=True,
Expand Down Expand Up @@ -396,7 +396,7 @@ def test_logger(test_client):
@mock.patch('elasticapm.base.TransactionsStore.should_collect')
def test_metrics_collection(should_collect, mock_send):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
)
Expand Down Expand Up @@ -431,7 +431,7 @@ def test_client_uses_sync_mode_when_master_process(is_master_process):
# HTTP transport, even if async_mode is True
is_master_process.return_value = True
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
async_mode=True,
Expand All @@ -446,7 +446,7 @@ def test_client_uses_sync_mode_when_master_process(is_master_process):
@mock.patch('elasticapm.base.TransactionsStore.should_collect')
def test_ignore_patterns(should_collect, mock_send):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
async_mode=True,
Expand All @@ -472,7 +472,7 @@ def test_ignore_patterns(should_collect, mock_send):
@mock.patch('elasticapm.base.Client.send_remote')
def test_disable_send(mock_send_remote):
client = Client(
servers=['http://example.com'],
server='http://example.com',
app_name='app_name',
secret_token='secret',
disable_send=True
Expand Down

0 comments on commit bf369ab

Please sign in to comment.