Instrumentation
It is common to want to integrate a third party instrumentation library or service with web services to monitor performance or enable cross-service request tracing. Granitic provides interfaces and framework hooks to support this.
There are three steps to supporting instrumentation:
- Creating a component that implements instrument.RequestInstrumentationManager
- Having that component return your own implementation of instrument.Instrumentor
- Configuring the HTTPServer facility to enable instrumentation
The first two steps are explained below, but configuration of the HTTPServer facility is documented here.
Request Instrumentation Manager
The role of the instrument.RequestInstrumentationManager is to allow Granitic to start instrumentation of a request, obtain an interface for recording discrete events within the request and access a method for stopping instrumentation.
You component must implement the method:
func Begin(ctx context.Context, res http.ResponseWriter, req *http.Request) (context.Context, Instrumentor, func())
Contexts
Although optional, it is recommended that your implementation of Begin
stores the Instrumentor
it creates in a new context
using the Granitic function instrument.AddInstrumentorToContext
. This means that any code in your application can retrieve
the Instrumentor
using the corresponding instrument.InstrumentorFromContext
method, or cleanly start new instrumentation
events using the instrument.Event
and instrument.Method
methods.
End function
Your begin method is required to return a function (most likely a closure) that can be called by Granitic to end instrumentation for a request.
Instrumentor
Your implementation of instrument.Instrumentor allows sub-sections of a request (events) to be instrumentated. For example, you may want to separately record the execution time of each method used by during your request.
Your code can interact directly with the Instrumentor
or indirectly using the helper functions instrument.Event
and instrument.Method
methods.
Handling goroutines
If your underlying instrumentation framework supports it, Instrumentor provides hooks to allow a child Instrumentor to
be spawned for a new goroutine (Fork
) and the results merged back into the overall request instrumentation (Integrate
).
If you do not support this feature, Integrate
should just return the same Instrumentor
it is passed and Integrate
should
do nothing.
Gaining access to additional data
Instrumentation starts as soon as the HTTPServer facility receives an HTTP request - before anything is known
about the request. As your Instrumentor
may need access to the additional information (the handler that processes the request, the ID associated
with the request), Granitic automatically calls the
Amend(additional Additional, value interface{})
method as new data is available. Your code must explicitly convert the interface{}
value passed into Amend
according to the value of
the instrument.Additional pseudo-enum.
Ending instrumentation
Granitic will call the end function created by the Begin
method on your instrument.RequestInstrumentationManager
when the HTTP request that is being instrumented is closed (more specifically when the httpserver.HTTPServer
’s handleAll
method exits).
It is highly recommended that any flushing actvitiy (sending the instrumentation data to storage) is handled asynchronously when the end function is called, otherwise the underlying HTTP request from your client’s web service call will not close until the flusing is complete.
It is also highly recommended that your instrument.RequestInstrumentationManager implements as many of Granitic’s lifecycle interfaces as is appropriate, so that connections to your instrumentation service are created during application startup and pending data is not lost when your application shuts down.
Next: Request identification
Prev: IAM