The Blackfire Go SDK is part of the Blackfire Go Module. You need to install the agent first.
To profile a CLI program with the Blackfire Go SDK, use this one liner at
the top of the main()
function:
Caution
Note that if you are calling os.Exit()
, the defer
will not be
executed. You would have to call blackfire.End()
before.
1 2 3 4 5 6 7 | import "github.com/blackfireio/go-blackfire" func main() { defer blackfire.Enable().End() // ... } |
This code does not profile anything unless you turn profiling on by using the
run
command of the Blackfire CLI:
1 2 3 4 5 | # Code is not profiled, and all Blackfire function calls are no-ops $ ./go_bin # Code is profiled $ blackfire run ./go_bin |
The Blackfire Probe is usually configured via environment variables, but you can customize the configuration when calling
the blackfire.Configure()
function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | import "github.com/blackfireio/go-blackfire" // Create a manual configuration object // All values set will take precedence on other configuration mechanism configuration := &blackfire.Configuration{ // Client ID to authenticate with the Blackfire API ClientID: "", // Client Token to authenticate with the Blackfire API ClientToken: "", // A zerolog Logger (default stderr) Logger: nil, // The maximum duration of a profile. A profile operation can never exceed // this duration (default 10 minutes). // This guards against runaway profile operations. MaxProfileDuration: 10 * time.Minute, // Time before dropping an unresponsive agent connection (default 250ms) AgentTimeout: 250 * time.Millisecond, // The socket to use when connecting to the Blackfire agent (default depends on OS) AgentSocket: "unix:///var/run/blackfire/agent.sock", // The configuration path to the Blackfire CLI ini file // Defaults to ~/.blackfire.ini ConfigFile: "", } // Configure the Blackfire probe with manual settings // and from the environment variables or via the $HOME/.blackfire.ini file blackfire.Configure(configuration) |
The Logger is automatically configured via the environment variables and defaults to stderr. You can explicitly set a zerolog Logger.
As a convenience, you can use the blackfire.NewLogger()
function to log to
a file:
1 2 3 4 5 6 7 8 9 | import "github.com/blackfireio/go-blackfire" // Creates a logger to a file with level 4 // Blackfire log levels: 4: debug, 3: info, 2: warning, 1: error logger := blackfire.NewLogger("/tmp/blackfire.log", 4) configuration := &blackfire.Configuration{ Logger: &logger, } blackfire.Configure(configuration) |
Use the special stderr
or stdout
strings to log to the console.
If you instrument the code like shown in the first example, the profiling is
only enabled when running the code via blackfire run
. When debugging, you
might prefer to turn profiling on by default:
Start profiling the code by calling EnableNow()
:
1 2 3 4 | import "github.com/blackfireio/go-blackfire" // Start the profiling blackfire.EnableNow() |
Stop profiling the code by calling Disable()
:
1 2 | // Stop the profiling blackfire.Disable() |
You can call Enable()
and Disable()
as many times as needed in your
code.
Calling End()
instead of Disable()
stops the profiling and forces the
collected data to be sent to Blackfire servers:
1 2 3 | // Stop the profiling // Send the result to Blackfire servers blackfire.End() |
End()
blocks until the profile is sent to the Blackfire’s servers. You can
also avoid the wait by using the EndNoWait()
function instead:
1 2 3 4 | // Stop the profiling // Send the result to Blackfire servers // Don't wait for the profile upload blackfire.EndNoWait() |
The Blackfire Go SDK exposes a profiling HTTP API through several Go HTTP handlers:
blackfire.EnableHandler()
;blackfire.DisableHandler()
;blackfire.EndHandler()
.The SDK also exposes a blackfire.DashboardHandler()
that provides a Web
interface from which you can start and stops profiling with a click.
To ease the integration into an existing Go web server, use the
blackfire.NewServeMux()
serve mux instead. It takes a prefix as an
argument. For instance, if you pass _blackfire
as a prefix, here is the
list of exposed endpoints:
/_blackfire/dashboard
gives access to the Web interface;/_blackfire/enable
starts profiling for 30 seconds;/_blackfire/enable?duration=1.5
starts profiling for 1.5
seconds. The duration
parameter accepts a float
;/_blackfire/disable
stops the current profiling session;/_blackfire/end
stops the profiling session and sends the
profiling data to Blackfire servers.The HTTP response returns a status code depending on the outcome:
The HTTP response body is a JSON file (application/problem+json
) containing
the following fields: status
, title
, and detail
.
Note
Don’t forget to secure these endpoints with some HTTP authentication.
The SDK allows you to control profiling with IPC Signals:
1 2 3 4 5 6 7 8 9 | import "github.com/blackfireio/go-blackfire" func installProfilerSignalHandlers() { // Starts profiling the current process for 5 seconds when receiving the SIGUSR1 signal. blackfire.EnableOnSignal(syscall.SIGUSR1, 5*time.Second) // Stops profiling and send profiling data to Blackfire when receiving the SIGUSR2 signal. blackfire.EndOnSignal(syscall.SIGUSR2) } |
Please note that a DisableOnSignal()
function is also available.
The Blackfire SDK exposes the EnableNowFor()
function that lets you profile
for a given duration:
1 2 3 4 5 6 | import "github.com/blackfireio/go-blackfire" // Profile for 200ms and send the data to Blackfire blackfire.EnableNowFor(200 * time.Millisecond) blackfire.End() |
Thanks to the Distributed Profiling feature, you can embed sub-profiles in the main profile.
For instance, when profiling command line programs that call sub-processes, you might want to trigger profiles for them as well. You can do so by generating a sub-profile request:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import "github.com/blackfireio/go-blackfire" cmd := exec.Command("some_bin") cmd.Env = env if env == nil { cmd.Env = os.Environ() } // Profile the command and attach it to the main profile // when on-demand profiling is enabled, this is only enable profiling // if the main program is profiled if id, err := blackfire.GenerateSubProfileQuery(); err == nil { cmd.Env = append(cmd.Env, "BLACKFIRE_QUERY="+id) } if err := cmd.Run(); err != nil { // ... } |
Sub-profiles also work for HTTP requests by adding a X-Blackfire-Query
HTTP
header (note that this is not supported by Go, but will work if the target
server is running Python or PHP).
1 2 3 4 5 | import "github.com/blackfireio/go-blackfire" if id, err := blackfire.GenerateSubProfileQuery(); err == nil { w.Header().Set("X-Blackfire-Query", id) } |