Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for loki.instance #403

Merged
merged 7 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cmd/incusd/api_1.0.go
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,8 @@ func doApi10UpdateTriggers(d *Daemon, nodeChanged, clusterChanged map[string]str
fallthrough
case "loki.api.ca_cert":
fallthrough
case "loki.instance":
fallthrough
case "loki.labels":
fallthrough
case "loki.loglevel":
Expand Down Expand Up @@ -984,12 +986,12 @@ func doApi10UpdateTriggers(d *Daemon, nodeChanged, clusterChanged map[string]str
}

if lokiChanged {
lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiLabels, lokiLoglevel, lokiTypes := clusterConfig.LokiServer()
lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiInstance, lokiLoglevel, lokiLabels, lokiTypes := clusterConfig.LokiServer()

if lokiURL == "" || lokiLoglevel == "" || len(lokiTypes) == 0 {
d.internalListener.RemoveHandler("loki")
} else {
err := d.setupLoki(lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiLabels, lokiLoglevel, lokiTypes)
err := d.setupLoki(lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiInstance, lokiLoglevel, lokiLabels, lokiTypes)
if err != nil {
return err
}
Expand Down
18 changes: 14 additions & 4 deletions cmd/incusd/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -762,22 +762,32 @@ func (d *Daemon) Init() error {
return nil
}

func (d *Daemon) setupLoki(URL string, cert string, key string, caCert string, labels []string, logLevel string, types []string) error {
func (d *Daemon) setupLoki(URL string, cert string, key string, caCert string, instanceName string, logLevel string, labels []string, types []string) error {
// Stop any existing loki client.
if d.lokiClient != nil {
d.lokiClient.Stop()
}

// Check basic requirements for starting a new client.
if URL == "" || logLevel == "" || len(types) == 0 {
return nil
}

// Validate the URL.
u, err := url.Parse(URL)
if err != nil {
return err
}

d.lokiClient = loki.NewClient(d.shutdownCtx, u, cert, key, caCert, labels, logLevel, types)
// Figure out the instance name.
if instanceName == "" {
instanceName = d.serverName
}

// Start a new client.
d.lokiClient = loki.NewClient(d.shutdownCtx, u, cert, key, caCert, instanceName, logLevel, labels, types)

// Attach the new client to the log handler.
d.internalListener.AddHandler("loki", d.lokiClient.HandleEvent)

return nil
Expand Down Expand Up @@ -1337,7 +1347,7 @@ func (d *Daemon) init() error {
d.proxy = proxy.FromConfig(d.globalConfig.ProxyHTTPS(), d.globalConfig.ProxyHTTP(), d.globalConfig.ProxyIgnoreHosts())

d.gateway.HeartbeatOfflineThreshold = d.globalConfig.OfflineThreshold()
lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiLabels, lokiLoglevel, lokiTypes := d.globalConfig.LokiServer()
lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiInstance, lokiLoglevel, lokiLabels, lokiTypes := d.globalConfig.LokiServer()
oidcIssuer, oidcClientID, oidcAudience := d.globalConfig.OIDCServer()
syslogSocketEnabled := d.localConfig.SyslogSocket()
openfgaAPIURL, openfgaAPIToken, openfgaStoreID, openFGAAuthorizationModelID := d.globalConfig.OpenFGA()
Expand All @@ -1348,7 +1358,7 @@ func (d *Daemon) init() error {

// Setup Loki logger.
if lokiURL != "" {
err = d.setupLoki(lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiLabels, lokiLoglevel, lokiTypes)
err = d.setupLoki(lokiURL, lokiUsername, lokiPassword, lokiCACert, lokiInstance, lokiLoglevel, lokiLabels, lokiTypes)
if err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2305,3 +2305,9 @@ Adds a `description` field to certificate.

Adds a new `virtio-blk` value for `io.bus` on `disk` devices which allows
for the attached disk to be connected to the `virtio-blk` bus.

## `loki_config_instance`

Adds a new `loki.instance` server configuration key to customize the `instance` field in Loki events.
This can be used to expose the name of the cluster rather than the individual system name sending
the event as that's usually already covered by the `location` field.
8 changes: 8 additions & 0 deletions doc/config_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1592,6 +1592,14 @@ Specify the protocol, name or IP and port. For example `https://loki.example.com

```

```{config:option} loki.instance server-loki
:defaultdesc: "Local server host name or cluster member name"
:scope: "global"
:shortdesc: "Name to use as the instance field in Loki events."
:type: "string"
This allows replacing the default instance value (server host name) by a more relevant value like a cluster identifier.
```

```{config:option} loki.labels server-loki
:scope: "global"
:shortdesc: "Labels for a Loki log entry"
Expand Down
4 changes: 2 additions & 2 deletions grafana/incus.json
Original file line number Diff line number Diff line change
Expand Up @@ -3694,7 +3694,7 @@
"uid": "${DS_LOKI}"
},
"editorMode": "builder",
"expr": "{app=\"incus\", type=\"lifecycle\"}",
"expr": "{app=\"incus\", type=\"lifecycle\", instance=\"$job\"}",
"queryType": "range",
"refId": "A"
}
Expand Down Expand Up @@ -3731,7 +3731,7 @@
"uid": "${DS_LOKI}"
},
"editorMode": "builder",
"expr": "{app=\"incus\", type=\"logging\"}",
"expr": "{app=\"incus\", type=\"logging\", instance=\"$job\"}",
"queryType": "range",
"refId": "A"
}
Expand Down
13 changes: 11 additions & 2 deletions internal/server/cluster/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func (c *Config) InstancesPlacementScriptlet() string {
}

// LokiServer returns all the Loki settings needed to connect to a server.
func (c *Config) LokiServer() (string, string, string, string, []string, string, []string) {
func (c *Config) LokiServer() (string, string, string, string, string, string, []string, []string) {
var types []string
var labels []string

Expand All @@ -195,7 +195,7 @@ func (c *Config) LokiServer() (string, string, string, string, []string, string,
labels = strings.Split(c.m.GetString("loki.labels"), ",")
}

return c.m.GetString("loki.api.url"), c.m.GetString("loki.auth.username"), c.m.GetString("loki.auth.password"), c.m.GetString("loki.api.ca_cert"), labels, c.m.GetString("loki.loglevel"), types
return c.m.GetString("loki.api.url"), c.m.GetString("loki.auth.username"), c.m.GetString("loki.auth.password"), c.m.GetString("loki.api.ca_cert"), c.m.GetString("loki.instance"), c.m.GetString("loki.loglevel"), labels, types
}

// ACME returns all ACME settings needed for certificate renewal.
Expand Down Expand Up @@ -593,6 +593,15 @@ var ConfigSchema = config.Schema{
// shortdesc: URL to the Loki server
"loki.api.url": {},

// gendoc:generate(entity=server, group=loki, key=loki.instance)
// This allows replacing the default instance value (server host name) by a more relevant value like a cluster identifier.
// ---
// type: string
// scope: global
// defaultdesc: Local server host name or cluster member name
// shortdesc: Name to use as the instance field in Loki events.
"loki.instance": {},

// gendoc:generate(entity=server, group=loki, key=loki.labels)
// Specify a comma-separated list of values that should be used as labels for a Loki log entry.
// ---
Expand Down
14 changes: 5 additions & 9 deletions internal/server/loki/loki.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"io"
"net/http"
"net/url"
"os"
"reflect"
"sort"
"strconv"
Expand Down Expand Up @@ -38,6 +37,7 @@ type config struct {
username string
password string
labels []string
instance string
logLevel string
timeout time.Duration
types []string
Expand All @@ -61,19 +61,20 @@ type Client struct {
}

// NewClient returns a Client.
func NewClient(ctx context.Context, url *url.URL, username string, password string, caCert string, labels []string, logLevel string, types []string) *Client {
func NewClient(ctx context.Context, u *url.URL, username string, password string, caCert string, instance string, logLevel string, labels []string, types []string) *Client {
client := Client{
cfg: config{
batchSize: 10 * 1024,
batchWait: 1 * time.Second,
caCert: caCert,
username: username,
password: password,
instance: instance,
labels: labels,
logLevel: logLevel,
timeout: 10 * time.Second,
types: types,
url: url,
url: u,
},
client: &http.Client{},
ctx: ctx,
Expand Down Expand Up @@ -227,17 +228,12 @@ func (c *Client) HandleEvent(event api.Event) {
return
}

hostname, err := os.Hostname()
if err != nil {
hostname = "none"
}

entry := entry{
labels: LabelSet{
"app": "incus",
"type": event.Type,
"location": event.Location,
"instance": hostname,
"instance": c.cfg.instance,
},
Entry: Entry{
Timestamp: event.Timestamp,
Expand Down
9 changes: 9 additions & 0 deletions internal/server/metadata/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,15 @@
"type": "string"
}
},
{
"loki.instance": {
"defaultdesc": "Local server host name or cluster member name",
"longdesc": "This allows replacing the default instance value (server host name) by a more relevant value like a cluster identifier.",
"scope": "global",
"shortdesc": "Name to use as the instance field in Loki events.",
"type": "string"
}
},
{
"loki.labels": {
"longdesc": "Specify a comma-separated list of values that should be used as labels for a Loki log entry.",
Expand Down
1 change: 1 addition & 0 deletions internal/version/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ var APIExtensions = []string{
"ovn_ssl_config",
"certificate_description",
"disk_io_bus_virtio_blk",
"loki_config_instance",
}

// APIExtensionsCount returns the number of available API extensions.
Expand Down
Loading