grafana

Services

A Grafana service encapsulates and exposes application logic to the rest of the application, through a set of related operations.

Before a service can start communicating with the rest of Grafana, it needs to be registered in the service registry.

The service registry keeps track of all available services during runtime. On start-up, Grafana uses the registry to build a dependency graph of services, a service graph.

Even though the services in Grafana do different things, they share a number of patterns. To better understand how a service works, let’s build one from scratch!

Create a service

To start building a service:

All services need to implement the Service interface:

type MyService struct {
}

func (s *MyService) Init() error {
    return nil
}

The Init method is used to initialize and configure the service to make it ready to use. Services that return an error halt Grafana’s startup process and cause the error to be logged as it exits.

Register a service

Every service needs to be registered with the application for it to be included in the service graph.

To register a service, call the registry.RegisterService function in an init function within your package.

func init() {
    registry.RegisterService(&MyService{})
}

init functions are only run whenever a package is imported, so we also need to import the package in the application. In the server.go file under pkg/cmd/grafana-server, import the package we just created:

import _ "github.com/grafana/grafana/pkg/services/mysvc"

Dependencies

Grafana uses the inject package to inject dependencies during runtime.

For example, to access the bus, add it to the MyService struct:

type MyService struct {
    Bus bus.Bus `inject:""`
}

You can also inject other services in the same way:

type MyService struct {
    Service other.Service `inject:""`
}

Note: Any injected dependency needs to be an exported field. Any unexported fields result in a runtime error.