baseplate
¶
The heart of the Baseplate framework is its telemetry system. Here’s an incomplete example of an application built with the framework:
def do_something(request):
result = request.db.execute("SELECT date('now');")
def make_app(app_config):
... snip ...
baseplate = Baseplate(app_config)
baseplate.configure_observers()
baseplate.configure_context({"db": SQLAlchemySession()})
... snip ...
When a request is made that routes to the do_something
handler, a
ServerSpan
is automatically created to track the time
spent processing the request in our application. If the incoming request has
trace headers, the constructed server span will have the same IDs as the
upstream service’s child span or else it will start a new trace with randomized
values.
When we call request.db.execute(...)
in the handler, Baseplate creates a
child Span
object to represent the time taken running
the query.
The creation of the server and child spans trigger callbacks on all the
ServerSpanObserver
and
SpanObserver
objects registered. Because we called
configure_observers()
in our setup, this means we
have observers that send telemetry about how our service is functioning.
Framework Configuration¶
At the root of each application is a single instance of
Baseplate
. This object can be integrated with
various other frameworks (e.g. Thrift, Pyramid, etc.) using one of the
integrations.
-
class
baseplate.
Baseplate
(app_config=None)[source]¶ The core of the Baseplate framework.
This class coordinates monitoring and tracing of service calls made to and from this service. See
baseplate.frameworks
for how to integrate it with the application framework you are using.-
__init__
(app_config=None)[source]¶ Initialize the core observability framework.
Parameters: app_config ( Optional
[Dict
[str
,str
]]) – The raw configuration dictionary for your application as supplied by baseplate-serve or baseplate-script. In addition to allowing framework-level configuration (described next), if this is supplied you do not need to pass the configuration again when callingconfigure_observers()
orconfigure_context()
.Baseplate services can identify themselves to downstream services in requests. The name a service identifies as defaults to the Python module the
Baseplate
object is instantiated in. To override the default, make sure you are passing in an app_config and configure the name in your INI file:[app:main] baseplate.service_name = foo_service ...
Return type: None
-
configure_observers
(app_config=None, module_name=None)[source]¶ Configure diagnostics observers based on application configuration.
This installs all the currently supported observers that have settings in the configuration file.
See
baseplate.observers
for the configuration settings available for each observer.Parameters: - app_config (
Optional
[Dict
[str
,str
]]) – The application configuration which should have settings for the error reporter. If not specified, the config must be passed to the Baseplate() constructor. - module_name (
Optional
[str
]) – Name of the root package of the application. If not specified, will be guessed from the package calling this function.
Return type: None
- app_config (
-
configure_context
(*args, **kwargs)[source]¶ Add a number of objects to each request’s context object.
Configure and attach multiple clients to the
RequestContext
in one place. This takes a full configuration spec likebaseplate.lib.config.parse_config()
and will attach the specified structure onto the context object each request.For example, a configuration like:
baseplate = Baseplate(app_config) baseplate.configure_context({ "cfg": { "doggo_is_good": config.Boolean, }, "cache": MemcachedClient(), "cassandra": { "foo": CassandraClient("foo_keyspace"), "bar": CassandraClient("bar_keyspace"), }, })
would build a context object that could be used like:
assert context.cfg.doggo_is_good == True context.cache.get("example") context.cassandra.foo.execute()
Parameters: - app_config – The raw stringy configuration dictionary.
- context_spec – A specification of what the configuration should look like.
Return type: None
-
add_to_context
(name, context_factory)[source]¶ Add an attribute to each request’s context object.
On each request, the factory will be asked to create an appropriate object to attach to the
RequestContext
.Parameters: - name (
str
) – The attribute on the context object to attach the created object to. This may also be used for metric/tracing purposes so it should be descriptive. - context_factory (baseplate.clients.ContextFactory) – A factory.
Return type: - name (
-
Per-request Context¶
Each time a new request comes in to be served, the time taken to handle the
request is represented by a new ServerSpan
instance.
During the course of handling that request, our application might make calls to
remote services or do expensive calculations, the time spent can be represented
by child Span
instances.
Spans have names and IDs and track their parent relationships. When calls are made to remote services, the information that identifies the local child span representing that service call is passed along to the remote service and becomes the server span in the remote service. This allows requests to be traced across the infrastructure.
Small bits of data, called annotations, can be attached to spans as well. This could be the URL fetched, or how many items were sent in a batch, or whatever else might be helpful.
-
class
baseplate.
RequestContext
(context_config, prefix=None, span=None, wrapped=None)[source]¶ The request context object.
The context object is passed into each request handler by the framework you’re using. In some cases (e.g. Pyramid) the request object will also inherit from another base class and carry extra framework-specific information.
Clients and configuration added to the context via
configure_context()
oradd_to_context()
will be available as an attribute on this object. To take advantage of Baseplate’s automatic monitoring, any interactions with external services should be done through these clients.
-
Baseplate.
make_context_object
()[source]¶ Make a context object for the request.
Return type: RequestContext
-
Baseplate.
make_server_span
(context, name, trace_info=None)[source]¶ Return a server span representing the request we are handling.
In a server, a server span represents the time spent on a single incoming request. Any calls made to downstream services will be new child spans of the server span, and the server span will in turn be the child span of whatever upstream request it is part of, if any.
Parameters: - context (
RequestContext
) – TheRequestContext
for this request. - name (
str
) – A name to identify the type of this request, e.g. a route or RPC method name. - trace_info (
Optional
[TraceInfo
]) – The trace context of this request as passed in from upstream. IfNone
, a new trace context will be generated.
Return type: - context (
-
Baseplate.
server_context
(name)[source]¶ Create a server span and return a context manager for its lifecycle.
This is a convenience wrapper around a common pattern seen outside of servers handling requests. For example, simple cron jobs or one-off scripts might want to create a temporary span and access the context object. Instead of calling
make_context_object()
followed bymake_server_span()
manually, this method bundles it all up for you:with baseplate.server_context("foo") as context: context.redis.ping()
Note
This should not be used within an existing span context (such as during request processing) as it creates a new span unrelated to any other ones.
Return type: Iterator
[RequestContext
]
-
class
baseplate.
ServerSpan
(trace_id, parent_id, span_id, sampled, flags, name, context, baseplate=None)[source]¶ A server span represents a request this server is handling.
The server span is available on the
RequestContext
during requests as thetrace
attribute.-
finish
(exc_info=None)¶ Record the end of the span.
Parameters: exc_info ( Optional
[Tuple
[Optional
[Type
[BaseException
]],Optional
[BaseException
],Optional
[traceback
]]]) – If the span ended because of an exception, this is the exception information. The default isNone
which indicates normal exit.Return type: None
-
incr_tag
(key, delta=1)¶ Increment a tag value on the span.
This is useful to count instances of an event in your application. In addition to showing up as a tag on the span, the value may also be aggregated separately as an independent counter.
Parameters: - key (
str
) – The name of the tag. - value – The amount to increment the value. Defaults to 1.
Return type: None
- key (
-
log
(name, payload=None)¶ Add a log entry to the span.
Log entries are timestamped events recording notable moments in the lifetime of a span.
Parameters: Return type: None
-
make_child
(name, local=False, component_name=None)¶ Return a child Span whose parent is this Span.
The child span can either be a local span representing an in-request operation or a span representing an outbound service call.
In a server, a local span represents the time spent within a local component performing an operation or set of operations. The local component is some grouping of business logic, which is then split up into operations which could each be wrapped in local spans.
Parameters: Return type:
-
register
(observer)¶ Register an observer to receive events from this span.
Return type: None
-
set_tag
(key, value)¶ Set a tag on the span.
Tags are arbitrary key/value pairs that add context and meaning to the span, such as a hostname or query string. Observers may interpret or ignore tags as they desire.
Parameters: Return type: None
-
start
()¶ Record the start of the span.
This notifies any observers that the span has started, which indicates that timers etc. should start ticking.
Spans also support the context manager protocol, for use with Python’s
with
statement. When the context is entered, the span callsstart()
and when the context is exited it automatically callsfinish()
.Return type: None
-
-
class
baseplate.
Span
(trace_id, parent_id, span_id, sampled, flags, name, context, baseplate=None)[source]¶ A span represents a single RPC within a system.
-
start
()[source]¶ Record the start of the span.
This notifies any observers that the span has started, which indicates that timers etc. should start ticking.
Spans also support the context manager protocol, for use with Python’s
with
statement. When the context is entered, the span callsstart()
and when the context is exited it automatically callsfinish()
.Return type: None
-
set_tag
(key, value)[source]¶ Set a tag on the span.
Tags are arbitrary key/value pairs that add context and meaning to the span, such as a hostname or query string. Observers may interpret or ignore tags as they desire.
Parameters: Return type: None
-
incr_tag
(key, delta=1)[source]¶ Increment a tag value on the span.
This is useful to count instances of an event in your application. In addition to showing up as a tag on the span, the value may also be aggregated separately as an independent counter.
Parameters: - key (
str
) – The name of the tag. - value – The amount to increment the value. Defaults to 1.
Return type: None
- key (
-
log
(name, payload=None)[source]¶ Add a log entry to the span.
Log entries are timestamped events recording notable moments in the lifetime of a span.
Parameters: Return type: None
-
finish
(exc_info=None)[source]¶ Record the end of the span.
Parameters: exc_info ( Optional
[Tuple
[Optional
[Type
[BaseException
]],Optional
[BaseException
],Optional
[traceback
]]]) – If the span ended because of an exception, this is the exception information. The default isNone
which indicates normal exit.Return type: None
-
-
class
baseplate.
TraceInfo
[source]¶ Trace context for a span.
If this request was made at the behest of an upstream service, the upstream service should have passed along trace information. This class is used for collecting the trace context and passing it along to the server span.
-
trace_id
¶ The ID of the whole trace. This will be the same for all downstream requests.
-
parent_id
¶ The ID of the parent span, or None if this is the root span.
-
span_id
¶ The ID of the current span. Should be unique within a trace.
-
sampled
¶ True if this trace was selected for sampling. Will be propagated to child spans.
-
flags
¶ A bit field of extra flags about this trace.
-
classmethod
new
()[source]¶ Generate IDs for a new initial server span.
This span has no parent and has a random ID. It cannot be correlated with any upstream requests.
Return type: TraceInfo
-
classmethod
from_upstream
(trace_id, parent_id, span_id, sampled, flags)[source]¶ Build a TraceInfo from individual headers.
Parameters: - trace_id (
Optional
[int
]) – The ID of the trace. - parent_id (
Optional
[int
]) – The ID of the parent span. - span_id (
Optional
[int
]) – The ID of this span within the tree. - sampled (
Optional
[bool
]) – Boolean flag to determine request sampling. - flags (
Optional
[int
]) – Bit flags for communicating feature flags downstream
Raises: ValueError
if any of the values are inappropriate.Return type: - trace_id (
-
Observers¶
To actually do something with all these spans, Baseplate provides observer interfaces which receive notification of events happening in the application via calls to various methods.
The base type of observer is BaseplateObserver
which can
be registered with the root Baseplate
instance using the
register()
method. Whenever a new server span is
created in your application (i.e. a new request comes in to be served) the
observer has its on_server_span_created()
method called with the relevant details. This method can register
ServerSpanObserver
instances with the new server span to
receive events as they happen.
Spans can be notified of five common events:
on_start()
, the span started.on_set_tag()
, a tag was set on the span.on_log()
, a log was entered on the span.on_finish()
, the span finished.on_child_span_created()
, a new child span was created.
New child spans are created in the application automatically by various client
library wrappers e.g. for a call to a remote service or database, and can also
be created explicitly for local actions like expensive computations. The
handler can register new SpanObserver
instances with the
new child span to receive events as they happen.
It’s up to the observers to attach meaning to these events. For example, the
metrics observer would start a timer
on_start()
and record the elapsed time to
StatsD on_finish()
.
-
Baseplate.
register
(observer)[source]¶ Register an observer.
Parameters: observer ( BaseplateObserver
) – An observer.Return type: None
-
class
baseplate.
BaseplateObserver
[source]¶ Interface for an observer that watches Baseplate.
-
on_server_span_created
(context, server_span)[source]¶ Do something when a server span is created.
Baseplate
calls this when a new request begins.Parameters: - context (
RequestContext
) – TheRequestContext
for this request. - server_span (
ServerSpan
) – The span representing this request.
Return type: None
- context (
-
-
class
baseplate.
ServerSpanObserver
[source]¶ Interface for an observer that watches the server span.
-
on_child_span_created
(span)¶ Do something when a child span is created.
SpanObserver
objects call this when a new child span is created.Parameters: span ( Span
) – The new child span.Return type: None
-
on_finish
(exc_info)¶ Do something when the observed span is finished.
Parameters: exc_info ( Optional
[Tuple
[Optional
[Type
[BaseException
]],Optional
[BaseException
],Optional
[traceback
]]]) – If the span ended because of an exception, the exception info. Otherwise,None
.Return type: None
-
on_incr_tag
(key, delta)¶ Do something when a tag value is incremented on the observed span.
Return type: None
-
on_log
(name, payload)¶ Do something when a log entry is added to the span.
Return type: None
-
on_set_tag
(key, value)¶ Do something when a tag is set on the observed span.
Return type: None
-
on_start
()¶ Do something when the observed span is started.
Return type: None
-
-
class
baseplate.
SpanObserver
[source]¶ Interface for an observer that watches a span.
-
on_set_tag
(key, value)[source]¶ Do something when a tag is set on the observed span.
Return type: None
-
on_incr_tag
(key, delta)[source]¶ Do something when a tag value is incremented on the observed span.
Return type: None
-
on_finish
(exc_info)[source]¶ Do something when the observed span is finished.
Parameters: exc_info ( Optional
[Tuple
[Optional
[Type
[BaseException
]],Optional
[BaseException
],Optional
[traceback
]]]) – If the span ended because of an exception, the exception info. Otherwise,None
.Return type: None
-
on_child_span_created
(span)[source]¶ Do something when a child span is created.
SpanObserver
objects call this when a new child span is created.Parameters: span ( Span
) – The new child span.Return type: None
-
Legacy Methods¶
-
Baseplate.
configure_logging
()[source]¶ Add request context to the logging system.
Deprecated since version 1.0: Use
configure_observers()
instead.Return type: None
-
Baseplate.
configure_metrics
(metrics_client)[source]¶ Send timing metrics to the given client.
This also adds a
baseplate.lib.metrics.Batch
object to themetrics
attribute on theRequestContext
where you can add your own application-specific metrics. The batch is automatically flushed at the end of the request.Deprecated since version 1.0: Use
configure_observers()
instead.Parameters: metrics_client ( Client
) – Metrics client to send request metrics to.Return type: None
-
Baseplate.
configure_tracing
(tracing_client)[source]¶ Collect and send span information for request tracing.
When configured, this will send tracing information automatically collected by Baseplate to the configured distributed tracing service.
Deprecated since version 1.0: Use
configure_observers()
instead.Parameters: tracing_client (baseplate.observers.tracing.TracingClient) – Tracing client to send request traces to. Return type: None
-
Baseplate.
configure_error_reporting
(client)[source]¶ Send reports for unexpected exceptions to the given client.
This also adds a
raven.Client
object to thesentry
attribute on theRequestContext
where you can send your own application-specific events.Deprecated since version 1.0: Use
configure_observers()
instead.Parameters: client (raven.Client) – A configured raven client. Return type: None