diff --git a/conf/defaults.ini b/conf/defaults.ini
index 583a3d90947..af81a9e01c9 100644
--- a/conf/defaults.ini
+++ b/conf/defaults.ini
@@ -208,6 +208,12 @@ rudderstack_write_key =
# Rudderstack data plane url, enabled only if rudderstack_write_key is also set
rudderstack_data_plane_url =
+# Application Insights connection string. Specify an URL string to enable this feature.
+application_insights_connection_string =
+
+# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
+application_insights_endpoint_url =
+
#################################### Security ############################
[security]
# disable creation of admin user on first start of grafana
diff --git a/docs/sources/administration/configuration.md b/docs/sources/administration/configuration.md
index 6a4a1eaeb5e..ccd81b165f7 100644
--- a/docs/sources/administration/configuration.md
+++ b/docs/sources/administration/configuration.md
@@ -468,6 +468,13 @@ Analytics ID here. By default this feature is disabled.
Google Tag Manager ID, only enabled if you enter an ID here.
+### application_insights_connection_string
+
+If you want to track Grafana usage via Azure Application Insights, then specify _your_ Application Insights connection string. Since the connection string contains semicolons, you need to wrap it in backticks (`). By default, tracking usage is disabled.
+
+### application_insights_endpoint_url
+ Optionally, use this option to override the default endpoint address for Application Insights data collecting. For details, refer to the [Azure documentation](https://docs.microsoft.com/en-us/azure/azure-monitor/app/custom-endpoints?tabs=js).
+
## [security]
diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts
index ddd10809874..bbcb3d45357 100644
--- a/packages/grafana-runtime/src/config.ts
+++ b/packages/grafana-runtime/src/config.ts
@@ -94,6 +94,8 @@ export class GrafanaBootConfig implements GrafanaConfig {
};
geomapDefaultBaseLayerConfig?: MapLayerOptions;
geomapDisableCustomBaseLayer?: boolean;
+ applicationInsightsConnectionString?: string;
+ applicationInsightsEndpointUrl?: string;
constructor(options: GrafanaBootConfig) {
const mode = options.bootData.user.lightTheme ? 'light' : 'dark';
diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go
index 1ef74759721..fbc4327b65c 100644
--- a/pkg/api/frontendsettings.go
+++ b/pkg/api/frontendsettings.go
@@ -197,38 +197,40 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i
}
jsonObj := map[string]interface{}{
- "defaultDatasource": defaultDS,
- "datasources": dataSources,
- "minRefreshInterval": setting.MinRefreshInterval,
- "panels": panels,
- "appUrl": hs.Cfg.AppURL,
- "appSubUrl": hs.Cfg.AppSubURL,
- "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
- "authProxyEnabled": setting.AuthProxyEnabled,
- "ldapEnabled": hs.Cfg.LDAPEnabled,
- "alertingEnabled": setting.AlertingEnabled,
- "alertingErrorOrTimeout": setting.AlertingErrorOrTimeout,
- "alertingNoDataOrNullValues": setting.AlertingNoDataOrNullValues,
- "alertingMinInterval": setting.AlertingMinInterval,
- "liveEnabled": hs.Cfg.LiveMaxConnections != 0,
- "autoAssignOrg": setting.AutoAssignOrg,
- "verifyEmailEnabled": setting.VerifyEmailEnabled,
- "sigV4AuthEnabled": setting.SigV4AuthEnabled,
- "exploreEnabled": setting.ExploreEnabled,
- "googleAnalyticsId": setting.GoogleAnalyticsId,
- "rudderstackWriteKey": setting.RudderstackWriteKey,
- "rudderstackDataPlaneUrl": setting.RudderstackDataPlaneUrl,
- "disableLoginForm": setting.DisableLoginForm,
- "disableUserSignUp": !setting.AllowUserSignUp,
- "loginHint": setting.LoginHint,
- "passwordHint": setting.PasswordHint,
- "externalUserMngInfo": setting.ExternalUserMngInfo,
- "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl,
- "externalUserMngLinkName": setting.ExternalUserMngLinkName,
- "viewersCanEdit": setting.ViewersCanEdit,
- "editorsCanAdmin": hs.Cfg.EditorsCanAdmin,
- "disableSanitizeHtml": hs.Cfg.DisableSanitizeHtml,
- "pluginsToPreload": pluginsToPreload,
+ "defaultDatasource": defaultDS,
+ "datasources": dataSources,
+ "minRefreshInterval": setting.MinRefreshInterval,
+ "panels": panels,
+ "appUrl": hs.Cfg.AppURL,
+ "appSubUrl": hs.Cfg.AppSubURL,
+ "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
+ "authProxyEnabled": setting.AuthProxyEnabled,
+ "ldapEnabled": hs.Cfg.LDAPEnabled,
+ "alertingEnabled": setting.AlertingEnabled,
+ "alertingErrorOrTimeout": setting.AlertingErrorOrTimeout,
+ "alertingNoDataOrNullValues": setting.AlertingNoDataOrNullValues,
+ "alertingMinInterval": setting.AlertingMinInterval,
+ "liveEnabled": hs.Cfg.LiveMaxConnections != 0,
+ "autoAssignOrg": setting.AutoAssignOrg,
+ "verifyEmailEnabled": setting.VerifyEmailEnabled,
+ "sigV4AuthEnabled": setting.SigV4AuthEnabled,
+ "exploreEnabled": setting.ExploreEnabled,
+ "googleAnalyticsId": setting.GoogleAnalyticsId,
+ "rudderstackWriteKey": setting.RudderstackWriteKey,
+ "rudderstackDataPlaneUrl": setting.RudderstackDataPlaneUrl,
+ "applicationInsightsConnectionString": hs.Cfg.ApplicationInsightsConnectionString,
+ "applicationInsightsEndpointUrl": hs.Cfg.ApplicationInsightsEndpointUrl,
+ "disableLoginForm": setting.DisableLoginForm,
+ "disableUserSignUp": !setting.AllowUserSignUp,
+ "loginHint": setting.LoginHint,
+ "passwordHint": setting.PasswordHint,
+ "externalUserMngInfo": setting.ExternalUserMngInfo,
+ "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl,
+ "externalUserMngLinkName": setting.ExternalUserMngLinkName,
+ "viewersCanEdit": setting.ViewersCanEdit,
+ "editorsCanAdmin": hs.Cfg.EditorsCanAdmin,
+ "disableSanitizeHtml": hs.Cfg.DisableSanitizeHtml,
+ "pluginsToPreload": pluginsToPreload,
"buildInfo": map[string]interface{}{
"hideVersion": hideVersion,
"version": version,
diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go
index 1bbd5fce7eb..6948e10c638 100644
--- a/pkg/setting/setting.go
+++ b/pkg/setting/setting.go
@@ -369,9 +369,11 @@ type Cfg struct {
Env string
// Analytics
- CheckForUpdates bool
- ReportingDistributor string
- ReportingEnabled bool
+ CheckForUpdates bool
+ ReportingDistributor string
+ ReportingEnabled bool
+ ApplicationInsightsConnectionString string
+ ApplicationInsightsEndpointUrl string
// LDAP
LDAPEnabled bool
@@ -908,6 +910,8 @@ func (cfg *Cfg) Load(args CommandLineArgs) error {
if len(cfg.ReportingDistributor) >= 100 {
cfg.ReportingDistributor = cfg.ReportingDistributor[:100]
}
+ cfg.ApplicationInsightsConnectionString = analytics.Key("application_insights_connection_string").String()
+ cfg.ApplicationInsightsEndpointUrl = analytics.Key("application_insights_endpoint_url").String()
if err := readAlertingSettings(iniFile); err != nil {
return err
diff --git a/public/app/app.ts b/public/app/app.ts
index 58fa46d24b8..c50432eb23b 100644
--- a/public/app/app.ts
+++ b/public/app/app.ts
@@ -48,6 +48,7 @@ import { getVariablesUrlParams } from './features/variables/getAllVariableValues
import getDefaultMonacoLanguages from '../lib/monaco-languages';
import { contextSrv } from './core/services/context_srv';
import { GAEchoBackend } from './core/services/echo/backends/analytics/GABackend';
+import { ApplicationInsightsBackend } from './core/services/echo/backends/analytics/ApplicationInsightsBackend';
import { RudderstackBackend } from './core/services/echo/backends/analytics/RudderstackBackend';
import { getAllOptionEditors } from './core/components/editors/registry';
@@ -182,6 +183,15 @@ function initEchoSrv() {
})
);
}
+
+ if (config.applicationInsightsConnectionString) {
+ registerEchoBackend(
+ new ApplicationInsightsBackend({
+ connectionString: config.applicationInsightsConnectionString,
+ endpointUrl: config.applicationInsightsEndpointUrl,
+ })
+ );
+ }
}
function addClassIfNoOverlayScrollbar() {
diff --git a/public/app/core/services/echo/backends/analytics/ApplicationInsightsBackend.ts b/public/app/core/services/echo/backends/analytics/ApplicationInsightsBackend.ts
new file mode 100644
index 00000000000..0405a4cecb7
--- /dev/null
+++ b/public/app/core/services/echo/backends/analytics/ApplicationInsightsBackend.ts
@@ -0,0 +1,48 @@
+import $ from 'jquery';
+import { EchoBackend, EchoEventType, isInteractionEvent, isPageviewEvent, PageviewEchoEvent } from '@grafana/runtime';
+
+export interface ApplicationInsightsBackendOptions {
+ connectionString: string;
+ endpointUrl?: string;
+}
+
+export class ApplicationInsightsBackend implements EchoBackend {
+ supportedEvents = [EchoEventType.Pageview];
+
+ constructor(public options: ApplicationInsightsBackendOptions) {
+ $.ajax({
+ url: 'https://js.monitor.azure.com/scripts/b/ai.2.min.js',
+ dataType: 'script',
+ cache: true,
+ }).done(function () {
+ var applicationInsightsOpts = {
+ config: {
+ connectionString: options.connectionString,
+ endpointUrl: options.endpointUrl,
+ },
+ };
+ var init = new (window as any).Microsoft.ApplicationInsights.ApplicationInsights(applicationInsightsOpts);
+ (window as any).applicationInsights = init.loadAppInsights();
+ });
+ }
+
+ addEvent = (e: PageviewEchoEvent) => {
+ if (!(window as any).applicationInsights) {
+ return;
+ }
+
+ if (isPageviewEvent(e)) {
+ (window as any).applicationInsights.trackPageView();
+ }
+
+ if (isInteractionEvent(e)) {
+ (window as any).applicationInsights.trackPageView({
+ name: e.payload.interactionName,
+ properties: e.payload.properties,
+ });
+ }
+ };
+
+ // Not using Echo buffering, addEvent above sends events to Application Insights as soon as they appear
+ flush = () => {};
+}