New Features
Tagged statsd metrics
Baseplate.py now includes an optional new metrics observer that emits
InfluxStatsD tagged metrics. This makes metric paths more discoverable and
allows for much cleaner metric queries. Additionally, you can change the
default list of tags to further slice your metrics as needed in your
application.
See upgrade instructions below and 452 for history
JSON Structured Logging
The default format of log entries emitted by Baseplate.py applications is now
JSON. This allows a variety of metadata to be included in log entries without
cluttering up the main message.
[See the logging observer documentation][logging observer] for full details of the available
fields.
[logging observer]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/observers/logging.html
See upgrade instructions below and 430 and 466 for history
New healthcheck protocol
Baseplate.py now supports different kinds of health checks. Currently
supported healthcheck probe types are: readiness, liveness, and startup. This
can be used to fine tune when the infrastructure should route traffic to your
application and when it should restart an unresponsive application.
See upgrade instructions below and 460 and 468 for history
Instrumented HTTP client
Requests is a library for making HTTP requests. Baseplate.py now provides two
wrappers for Requests: the "external" client is suitable for communication with
third party, potentially untrusted, services; the "internal" client is suitable
for talking to first-party services and automatically includes trace and edge
context data in requests. Baseplate.py uses [Advocate] to prevent the external
client from talking to internal services and vice versa.
See [`baseplate.clients.requests` documentation] and 465 and 479 for history
[Advocate]: https://github.com/JordanMilne/Advocate
[`baseplate.clients.requests` documentation]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/clients/requests.html
Changes
* The [KombuProducer] client now passes a `secrets` parameter through to
`connection_from_config` (451)
* Baseplate.thrift now contains a standardized typedef for timestamp fields.
Use this in your services to communicate the timestamp format expected. (458)
* A new convenience function
[`baseplate.lib.datetime.epoch_milliseconds_to_datetime`][emtd] parses
milliseconds since the UNIX epoch into a datetime object (461).
* When using a pre-release of Thrift v0.14, the Thrift connection pool will now
test if the connection was closed by the remote side before returning a
connection to the application for use. This should reduce the frequency of
spurious RPC failures. (also in 1.3.5, 464)
* Many additions and changes to the documentation. Check out the new [Startup
Sequence] and [FAQ] pages. (467, 469, 471, 473)
* Unblock use of `lock()` on redis client wrapper (480)
[KombuProducer]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/clients/kombu.html#baseplate.clients.kombu.KombuProducer
[emtd]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/lib/datetime.html#baseplate.lib.datetime.epoch_milliseconds_to_datetime
[Startup Sequence]: https://baseplate.readthedocs.io/en/v1.4.0/guide/startup.html
[FAQ]: https://baseplate.readthedocs.io/en/v1.4.0/guide/faq.html
Bug fixes
* Fix bug where thrift pool gains an extra slot after the retry policy is
exhausted while trying to connect (also in 1.3.1, 447)
* The event publisher sidecar will no longer crash when events are rejected
because of validation errors (also in 1.3.1, 450)
* Fix extra connection slots being returned to thrift connection pool when
server timeout occurs while waiting for a slot (also in 1.3.2, 431)
* Properly handle base64-encoded edge context headers in Pyramid services (also
in 1.3.2, 449, 456)
* Fix breaking behavior introduced in 1.2 around server timeouts. Rather than
defaulting to a 10 second timeout if not specified in config, timeouts are
defaulted to off and a deprecation warning is emitted. Please do [configure
timeouts] for your service as they're an important mitigation for overloads
during production incidents. (also in 1.3.3, 446)
[configure timeouts]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/observers/timeout.html
Upgrading
This release should not contain any breaking changes but following are notes on
how to upgrade to take advantage of the new features.
Tagged statsd metrics
**For reddit employees, search "Baseplate Tags Guide (v1.4+)" in Confluence to
get a comprehensive upgrade guide or come to baseplate-tags-support in Slack.**
In your application's configuration file, remove `metrics.namespace`
configuration and add `metrics.tagging = true`. See [the tagged metrics
observer documentation][taggedmetrics] for full information.
[taggedmetrics]: https://baseplate.readthedocs.io/en/v1.4.0/api/baseplate/observers/tagged_statsd.html
JSON Structured Logging
By default, no changes should be necessary to get JSON formatted logs. However,
if your service is overriding the default [`logging.Formatter`] (e.g. [by
configuring it in your INI file][logging.config]) you may need to amend your
configuration. See [python-json-logger's documentation] for more information. Note that
Baseplate.py supplies a custom formatter subclass that you can find at `baseplate.lib.log_formatter.CustomJsonFormatter`.
[`logging.Formatter`]: https://docs.python.org/3/library/logging.html#formatter-objects
[logging.config]: https://docs.python.org/3/library/logging.config.html#logging.config.fileConfig
[python-json-logger's documentation]: https://github.com/madzak/python-json-logger#using-a-config-file
New healthcheck protocol
To support the new healthcheck, you'll need to make a few small changes:
In your Thrift IDL, change the base your service extends to `BaseplateServiceV2`:
diff
--- a/myservice/myservice.thrift
+++ b/myservice/myservice.thrift
-service MyService extends baseplate.BaseplateService {
+service MyService extends baseplate.BaseplateServiceV2 {
Then add the new `request` parameter to your service's `is_healthy` method and
use its `probe` field:
diff
--- a/myservice/__init__.py
+++ b/myservice/__init__.py
-6,12 +6,15 import re
from typing import Dict
from typing import List
+from typing import Optional
from baseplate import Baseplate
from baseplate import RequestContext
from baseplate.clients.redis import RedisClient
from baseplate.frameworks.thrift import baseplateify_processor
from baseplate.lib import config
+from baseplate.thrift.ttypes import IsHealthyProbe
+from baseplate.thrift.ttypes import IsHealthyRequest
from thrift.Thrift import TProcessor
from .myservice_thrift import MyService
-45,8 +48,13 class Handler:
- def is_healthy(self, context: RequestContext) -> bool:
- return context.redis.ping()
+ def is_healthy(
+ self, context: RequestContext, request: Optional[IsHealthyRequest] = None
+ ) -> bool:
+ if request.probe == IsHealthyProbe.LIVENESS:
+ return True
+ else: treat all other probe types as READINESS
+ return context.redis.ping()