diff --git a/conf/defaults.ini b/conf/defaults.ini
index 855f1b90072..750cc23a329 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -670,6 +670,12 @@ disable_total_stats = false
basic_auth_username =
basic_auth_password =
+# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
+# can expose more information about the Grafana instance.
+[metrics.environment_info]
+#exampleLabel1 = exampleValue1
+#exampleLabel2 = exampleValue2
+
# Send internal Grafana metrics to graphite
[metrics.graphite]
# Enable by setting the address setting (ex localhost:2003)
diff --git a/conf/sample.ini b/conf/sample.ini
index 41c5e96a853..1ebd84a236f 100644
--- a/conf/sample.ini
+++ b/conf/sample.ini
@@ -664,6 +664,12 @@
; basic_auth_username =
; basic_auth_password =
+# Metrics environment info adds dimensions to the `grafana_environment_info` metric, which
+# can expose more information about the Grafana instance.
+[metrics.environment_info]
+#exampleLabel1 = exampleValue1
+#exampleLabel2 = exampleValue2
+
# Send internal metrics to Graphite
[metrics.graphite]
# Enable by setting the address setting (ex localhost:2003)
diff --git a/docs/sources/administration/configuration.md b/docs/sources/administration/configuration.md
index cf95a3eb508..e7bbdcb8827 100644
--- a/docs/sources/administration/configuration.md
+++ b/docs/sources/administration/configuration.md
@@ -399,7 +399,7 @@ The length of time that Grafana will wait for a successful TLS handshake with th
### expect_continue_timeout_seconds
-The length of time that Grafana will wait for a datasource’s first response headers after fully writing the request headers, if the request has an “Expect: 100-continue” header. A value of `0` will result in the body being sent immediately. Default is `1` second. For more details check the [Transport.ExpectContinueTimeout](https://golang.org/pkg/net/http/#Transport.ExpectContinueTimeout) documentation.
+The length of time that Grafana will wait for a datasource’s first response headers after fully writing the request headers, if the request has an “Expect: 100-continue” header. A value of `0` will result in the body being sent immediately. Default is `1` second. For more details check the [Transport.ExpectContinueTimeout](https://golang.org/pkg/net/http/#Transport.ExpectContinueTimeout) documentation.
### max_idle_connections
@@ -625,7 +625,7 @@ Default is `false`.
### user_invite_max_lifetime_duration
-The duration in time a user invitation remains valid before expiring.
+The duration in time a user invitation remains valid before expiring.
This setting should be expressed as a duration. Examples: 6h (hours), 2d (days), 1w (week).
Default is `24h` (24 hours). The minimum supported duration is `15m` (15 minutes).
@@ -1075,6 +1075,15 @@ If both are set, then basic authentication is required to access the metrics end
+## [metrics.environment_info]
+
+Adds dimensions to the `grafana_environment_info` metric, which can expose more information about the Grafana instance.
+
+```
+; exampleLabel1 = exampleValue1
+; exampleLabel2 = exampleValue2
+```
+
## [metrics.graphite]
Use these options if you want to send internal Grafana metrics to Graphite.
diff --git a/pkg/infra/metrics/metrics.go b/pkg/infra/metrics/metrics.go
index 31d2fcb4182..edaf70ceef5 100644
--- a/pkg/infra/metrics/metrics.go
+++ b/pkg/infra/metrics/metrics.go
@@ -513,6 +513,26 @@ func SetBuildInformation(version, revision, branch string) {
grafanaBuildVersion.WithLabelValues(version, revision, branch, runtime.Version(), edition).Set(1)
}
+// SetEnvironmentInformation exposes environment values provided by the operators as an `_info` metric.
+// If there are no environment metrics labels configured, this metric will not be exposed.
+func SetEnvironmentInformation(labels map[string]string) error {
+ if len(labels) == 0 {
+ return nil
+ }
+
+ grafanaEnvironmentInfo := prometheus.NewGauge(prometheus.GaugeOpts{
+ Name: "environment_info",
+ Help: "A metric with a constant '1' value labeled by environment information about the running instance.",
+ Namespace: ExporterName,
+ ConstLabels: labels,
+ })
+
+ prometheus.MustRegister(grafanaEnvironmentInfo)
+
+ grafanaEnvironmentInfo.Set(1)
+ return nil
+}
+
func SetPluginBuildInformation(pluginID, pluginType, version string) {
grafanaPluginBuildInfoDesc.WithLabelValues(pluginID, pluginType, version).Set(1)
}
diff --git a/pkg/server/server.go b/pkg/server/server.go
index feeaabc961b..b272e100352 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -22,6 +22,7 @@ import (
_ "github.com/grafana/grafana/pkg/extensions"
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
+ "github.com/grafana/grafana/pkg/infra/metrics"
_ "github.com/grafana/grafana/pkg/infra/metrics"
_ "github.com/grafana/grafana/pkg/infra/remotecache"
_ "github.com/grafana/grafana/pkg/infra/serverlock"
@@ -117,6 +118,9 @@ func (s *Server) init(cfg *Config) error {
s.loadConfiguration()
s.writePIDFile()
+ if err := metrics.SetEnvironmentInformation(s.cfg.MetricsGrafanaEnvironmentInfo); err != nil {
+ return err
+ }
login.Init()
social.NewOAuthService()
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index c6d1d6f5aa8..6dddd32cc94 100644
--- a/pkg/setting/setting.go
+++ b/pkg/setting/setting.go
@@ -17,6 +17,7 @@ import (
"time"
"github.com/go-macaron/session"
+ "github.com/prometheus/common/model"
ini "gopkg.in/ini.v1"
"github.com/grafana/grafana/pkg/components/gtime"
@@ -267,17 +268,20 @@ type Cfg struct {
CookieSameSiteDisabled bool
CookieSameSiteMode http.SameSite
- TempDataLifetime time.Duration
+ TempDataLifetime time.Duration
+ PluginsEnableAlpha bool
+ PluginsAppsSkipVerifyTLS bool
+ PluginSettings PluginSettings
+ PluginsAllowUnsigned []string
+ DisableSanitizeHtml bool
+ EnterpriseLicensePath string
+
+ // Metrics
MetricsEndpointEnabled bool
MetricsEndpointBasicAuthUsername string
MetricsEndpointBasicAuthPassword string
MetricsEndpointDisableTotalStats bool
- PluginsEnableAlpha bool
- PluginsAppsSkipVerifyTLS bool
- PluginSettings PluginSettings
- PluginsAllowUnsigned []string
- DisableSanitizeHtml bool
- EnterpriseLicensePath string
+ MetricsGrafanaEnvironmentInfo map[string]string
// Dashboards
DefaultHomeDashboardPath string
@@ -411,6 +415,29 @@ func applyEnvVariableOverrides(file *ini.File) error {
return nil
}
+func (cfg *Cfg) readGrafanaEnvironmentMetrics() error {
+ environmentMetricsSection := cfg.Raw.Section("metrics.environment_info")
+ keys := environmentMetricsSection.Keys()
+ cfg.MetricsGrafanaEnvironmentInfo = make(map[string]string, len(keys))
+
+ for _, key := range keys {
+ labelName := model.LabelName(key.Name())
+ labelValue := model.LabelValue(key.Value())
+
+ if !labelName.IsValid() {
+ return fmt.Errorf("invalid label name in [metrics.environment_info] configuration. name %q", labelName)
+ }
+
+ if !labelValue.IsValid() {
+ return fmt.Errorf("invalid label value in [metrics.environment_info] configuration. name %q value %q", labelName, labelValue)
+ }
+
+ cfg.MetricsGrafanaEnvironmentInfo[string(labelName)] = string(labelValue)
+ }
+
+ return nil
+}
+
func (cfg *Cfg) readAnnotationSettings() {
dashboardAnnotation := cfg.Raw.Section("annotations.dashboard")
apiIAnnotation := cfg.Raw.Section("annotations.api")
@@ -781,6 +808,9 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
cfg.readSmtpSettings()
cfg.readQuotaSettings()
cfg.readAnnotationSettings()
+ if err := cfg.readGrafanaEnvironmentMetrics(); err != nil {
+ return err
+ }
if VerifyEmailEnabled && !cfg.Smtp.Enabled {
log.Warnf("require_email_validation is enabled but smtp is disabled")