EchoSrv: Enable auto route tracking for Azure App Insights (#113354)

* Echo: Enable auto route tracking with Azure App Insights

* Add server config option to disable auto route tracking

* fix not using minified js
This commit is contained in:
Josh Hunt
2025-11-11 16:33:46 +00:00
committed by GitHub
parent 4ae1774e1f
commit 96f34f8f56
13 changed files with 131 additions and 108 deletions
+4
View File
@@ -340,6 +340,10 @@ application_insights_connection_string =
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
application_insights_endpoint_url =
# Optional, defaults to true. Configure automatic route tracking for single page applications in Application Insights.
# See https://learn.microsoft.com/en-us/azure/azure-monitor/app/application-insights-faq#is-there-a-way-to-see-fewer-events-per-transaction-when-i-use-the-application-insights-javascript-sdk
application_insights_auto_route_tracking = true
# Controls if the UI contains any links to user feedback forms
feedback_links_enabled = true
+4
View File
@@ -333,6 +333,10 @@
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
;application_insights_endpoint_url =
# Optional, defaults to true. Configure automatic route tracking for single page applications in Application Insights.
# See https://learn.microsoft.com/en-us/azure/azure-monitor/app/application-insights-faq#is-there-a-way-to-see-fewer-events-per-transaction-when-i-use-the-application-insights-javascript-sdk
;application_insights_auto_route_tracking =
# Controls if the UI contains any links to user feedback forms
;feedback_links_enabled = true
+1 -1
View File
@@ -30,7 +30,7 @@ server {
server_name _;
otel_trace on;
otel_trace_context inject;
otel_trace_context propagate;
otel_span_name "$request_method Request";
location ~ ^/-/down/?$ {
@@ -657,12 +657,16 @@ If you want to track Grafana usage via Azure Application Insights, then specify
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).
<hr />
#### `application_insights_auto_route_tracking`
Optionally, use this to configure `enableAutoRouteTracking` in Azure Application Insights. Defaults to `true`. For more details, refer to the [Azure documentation](https://learn.microsoft.com/en-us/azure/azure-monitor/app/application-insights-faq#is-there-a-way-to-see-fewer-events-per-transaction-when-i-use-the-application-insights-javascript-sdk)
#### `feedback_links_enabled`
Set to `false` to remove all feedback links from the UI. Default is `true`.
<hr />
### `[security]`
#### `disable_initial_admin_creation`
@@ -291,6 +291,7 @@ export interface GrafanaConfig {
rudderstackIntegrationsUrl: string;
applicationInsightsConnectionString: string;
applicationInsightsEndpointUrl: string;
applicationInsightsAutoRouteTracking: boolean;
analyticsConsoleReporting: boolean;
rendererAvailable: boolean;
rendererVersion: string;
+1
View File
@@ -205,6 +205,7 @@ export class GrafanaBootConfig {
};
applicationInsightsConnectionString?: string;
applicationInsightsEndpointUrl?: string;
applicationInsightsAutoRouteTracking?: boolean;
recordedQueries = {
enabled: true,
};
+22 -21
View File
@@ -208,27 +208,28 @@ type FrontendSettingsDTO struct {
DashboardPerformanceMetrics []string `json:"dashboardPerformanceMetrics"`
PanelSeriesLimit int `json:"panelSeriesLimit"`
FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"`
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"`
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"`
DisableLoginForm bool `json:"disableLoginForm"`
DisableUserSignUp bool `json:"disableUserSignUp"`
LoginHint string `json:"loginHint"`
PasswordHint string `json:"passwordHint"`
ExternalUserMngInfo string `json:"externalUserMngInfo"`
ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"`
ExternalUserMngLinkName string `json:"externalUserMngLinkName"`
ExternalUserMngAnalytics bool `json:"externalUserMngAnalytics"`
ExternalUserMngAnalyticsParams string `json:"externalUserMngAnalyticsParams"`
ViewersCanEdit bool `json:"viewersCanEdit"`
DisableSanitizeHtml bool `json:"disableSanitizeHtml"`
TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"`
CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"`
EnableFrontendSandboxForPlugins []string `json:"enableFrontendSandboxForPlugins"`
PluginRestrictedAPIsAllowList map[string][]string `json:"pluginRestrictedAPIsAllowList"`
PluginRestrictedAPIsBlockList map[string][]string `json:"pluginRestrictedAPIsBlockList"`
ExploreDefaultTimeOffset string `json:"exploreDefaultTimeOffset"`
ExploreHideLogsDownload bool `json:"exploreHideLogsDownload"`
FeedbackLinksEnabled bool `json:"feedbackLinksEnabled"`
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString"`
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl"`
ApplicationInsightsAutoRouteTracking bool `json:"applicationInsightsAutoRouteTracking"`
DisableLoginForm bool `json:"disableLoginForm"`
DisableUserSignUp bool `json:"disableUserSignUp"`
LoginHint string `json:"loginHint"`
PasswordHint string `json:"passwordHint"`
ExternalUserMngInfo string `json:"externalUserMngInfo"`
ExternalUserMngLinkUrl string `json:"externalUserMngLinkUrl"`
ExternalUserMngLinkName string `json:"externalUserMngLinkName"`
ExternalUserMngAnalytics bool `json:"externalUserMngAnalytics"`
ExternalUserMngAnalyticsParams string `json:"externalUserMngAnalyticsParams"`
ViewersCanEdit bool `json:"viewersCanEdit"`
DisableSanitizeHtml bool `json:"disableSanitizeHtml"`
TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled"`
CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled"`
EnableFrontendSandboxForPlugins []string `json:"enableFrontendSandboxForPlugins"`
PluginRestrictedAPIsAllowList map[string][]string `json:"pluginRestrictedAPIsAllowList"`
PluginRestrictedAPIsBlockList map[string][]string `json:"pluginRestrictedAPIsBlockList"`
ExploreDefaultTimeOffset string `json:"exploreDefaultTimeOffset"`
ExploreHideLogsDownload bool `json:"exploreHideLogsDownload"`
Auth FrontendSettingsAuthDTO `json:"auth"`
+48 -47
View File
@@ -197,53 +197,54 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
featureToggles["topnav"] = true
frontendSettings := &dtos.FrontendSettingsDTO{
DefaultDatasource: defaultDS,
Datasources: dataSources,
MinRefreshInterval: hs.Cfg.MinRefreshInterval,
Panels: panels,
Apps: apps,
AppUrl: hs.Cfg.AppURL,
AppSubUrl: hs.Cfg.AppSubURL,
AllowOrgCreate: (hs.Cfg.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
AuthProxyEnabled: hs.Cfg.AuthProxy.Enabled,
LdapEnabled: hs.Cfg.LDAPAuthEnabled,
JwtHeaderName: hs.Cfg.JWTAuth.HeaderName,
JwtUrlLogin: hs.Cfg.JWTAuth.URLLogin,
LiveEnabled: hs.Cfg.LiveMaxConnections != 0,
LiveMessageSizeLimit: hs.Cfg.LiveMessageSizeLimit,
AutoAssignOrg: hs.Cfg.AutoAssignOrg,
VerifyEmailEnabled: hs.Cfg.VerifyEmailEnabled,
SigV4AuthEnabled: hs.Cfg.SigV4AuthEnabled,
AzureAuthEnabled: hs.Cfg.AzureAuthEnabled,
RbacEnabled: true,
ExploreEnabled: hs.Cfg.ExploreEnabled,
HelpEnabled: hs.Cfg.HelpEnabled,
ProfileEnabled: hs.Cfg.ProfileEnabled,
NewsFeedEnabled: hs.Cfg.NewsFeedEnabled,
QueryHistoryEnabled: hs.Cfg.QueryHistoryEnabled,
GoogleAnalyticsId: hs.Cfg.GoogleAnalyticsID,
GoogleAnalytics4Id: hs.Cfg.GoogleAnalytics4ID,
GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews,
RudderstackWriteKey: hs.Cfg.RudderstackWriteKey,
RudderstackDataPlaneUrl: hs.Cfg.RudderstackDataPlaneURL,
RudderstackSdkUrl: hs.Cfg.RudderstackSDKURL,
RudderstackConfigUrl: hs.Cfg.RudderstackConfigURL,
RudderstackIntegrationsUrl: hs.Cfg.RudderstackIntegrationsURL,
AnalyticsConsoleReporting: hs.Cfg.FrontendAnalyticsConsoleReporting,
DashboardPerformanceMetrics: hs.Cfg.DashboardPerformanceMetrics,
PanelSeriesLimit: hs.Cfg.PanelSeriesLimit,
FeedbackLinksEnabled: hs.Cfg.FeedbackLinksEnabled,
ApplicationInsightsConnectionString: hs.Cfg.ApplicationInsightsConnectionString,
ApplicationInsightsEndpointUrl: hs.Cfg.ApplicationInsightsEndpointUrl,
DisableLoginForm: hs.Cfg.DisableLoginForm,
DisableUserSignUp: !hs.Cfg.AllowUserSignUp,
LoginHint: hs.Cfg.LoginHint,
PasswordHint: hs.Cfg.PasswordHint,
ExternalUserMngInfo: hs.Cfg.ExternalUserMngInfo,
ExternalUserMngLinkUrl: hs.Cfg.ExternalUserMngLinkUrl,
ExternalUserMngLinkName: hs.Cfg.ExternalUserMngLinkName,
ExternalUserMngAnalytics: hs.Cfg.ExternalUserMngAnalytics,
ExternalUserMngAnalyticsParams: hs.Cfg.ExternalUserMngAnalyticsParams,
DefaultDatasource: defaultDS,
Datasources: dataSources,
MinRefreshInterval: hs.Cfg.MinRefreshInterval,
Panels: panels,
Apps: apps,
AppUrl: hs.Cfg.AppURL,
AppSubUrl: hs.Cfg.AppSubURL,
AllowOrgCreate: (hs.Cfg.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin,
AuthProxyEnabled: hs.Cfg.AuthProxy.Enabled,
LdapEnabled: hs.Cfg.LDAPAuthEnabled,
JwtHeaderName: hs.Cfg.JWTAuth.HeaderName,
JwtUrlLogin: hs.Cfg.JWTAuth.URLLogin,
LiveEnabled: hs.Cfg.LiveMaxConnections != 0,
LiveMessageSizeLimit: hs.Cfg.LiveMessageSizeLimit,
AutoAssignOrg: hs.Cfg.AutoAssignOrg,
VerifyEmailEnabled: hs.Cfg.VerifyEmailEnabled,
SigV4AuthEnabled: hs.Cfg.SigV4AuthEnabled,
AzureAuthEnabled: hs.Cfg.AzureAuthEnabled,
RbacEnabled: true,
ExploreEnabled: hs.Cfg.ExploreEnabled,
HelpEnabled: hs.Cfg.HelpEnabled,
ProfileEnabled: hs.Cfg.ProfileEnabled,
NewsFeedEnabled: hs.Cfg.NewsFeedEnabled,
QueryHistoryEnabled: hs.Cfg.QueryHistoryEnabled,
GoogleAnalyticsId: hs.Cfg.GoogleAnalyticsID,
GoogleAnalytics4Id: hs.Cfg.GoogleAnalytics4ID,
GoogleAnalytics4SendManualPageViews: hs.Cfg.GoogleAnalytics4SendManualPageViews,
RudderstackWriteKey: hs.Cfg.RudderstackWriteKey,
RudderstackDataPlaneUrl: hs.Cfg.RudderstackDataPlaneURL,
RudderstackSdkUrl: hs.Cfg.RudderstackSDKURL,
RudderstackConfigUrl: hs.Cfg.RudderstackConfigURL,
RudderstackIntegrationsUrl: hs.Cfg.RudderstackIntegrationsURL,
AnalyticsConsoleReporting: hs.Cfg.FrontendAnalyticsConsoleReporting,
DashboardPerformanceMetrics: hs.Cfg.DashboardPerformanceMetrics,
PanelSeriesLimit: hs.Cfg.PanelSeriesLimit,
FeedbackLinksEnabled: hs.Cfg.FeedbackLinksEnabled,
ApplicationInsightsConnectionString: hs.Cfg.ApplicationInsightsConnectionString,
ApplicationInsightsEndpointUrl: hs.Cfg.ApplicationInsightsEndpointUrl,
ApplicationInsightsAutoRouteTracking: hs.Cfg.ApplicationInsightsAutoRouteTracking,
DisableLoginForm: hs.Cfg.DisableLoginForm,
DisableUserSignUp: !hs.Cfg.AllowUserSignUp,
LoginHint: hs.Cfg.LoginHint,
PasswordHint: hs.Cfg.PasswordHint,
ExternalUserMngInfo: hs.Cfg.ExternalUserMngInfo,
ExternalUserMngLinkUrl: hs.Cfg.ExternalUserMngLinkUrl,
ExternalUserMngLinkName: hs.Cfg.ExternalUserMngLinkName,
ExternalUserMngAnalytics: hs.Cfg.ExternalUserMngAnalytics,
ExternalUserMngAnalyticsParams: hs.Cfg.ExternalUserMngAnalyticsParams,
//nolint:staticcheck // ViewersCanEdit is deprecated but still used for backward compatibility
ViewersCanEdit: hs.Cfg.ViewersCanEdit,
DisableSanitizeHtml: hs.Cfg.DisableSanitizeHtml,
+3 -2
View File
@@ -38,8 +38,9 @@ type FSFrontendSettings struct {
AnalyticsConsoleReporting bool `json:"analyticsConsoleReporting,omitempty"`
GrafanaJavascriptAgent setting.GrafanaJavascriptAgent `json:"grafanaJavascriptAgent,omitempty"`
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString,omitempty"`
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl,omitempty"`
ApplicationInsightsConnectionString string `json:"applicationInsightsConnectionString,omitempty"`
ApplicationInsightsEndpointUrl string `json:"applicationInsightsEndpointUrl,omitempty"`
ApplicationInsightsAutoRouteTracking bool `json:"applicationInsightsAutoRouteTracking,omitempty"`
TrustedTypesDefaultPolicyEnabled bool `json:"trustedTypesDefaultPolicyEnabled,omitempty"`
CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled,omitempty"`
+29 -28
View File
@@ -67,34 +67,35 @@ func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets, li
// subset of frontend settings needed for the login page
// TODO what about enterprise settings here?
frontendSettings := FSFrontendSettings{
AnalyticsConsoleReporting: cfg.FrontendAnalyticsConsoleReporting,
AnonymousEnabled: cfg.Anonymous.Enabled,
ApplicationInsightsConnectionString: cfg.ApplicationInsightsConnectionString,
ApplicationInsightsEndpointUrl: cfg.ApplicationInsightsEndpointUrl,
AuthProxyEnabled: cfg.AuthProxy.Enabled,
AutoAssignOrg: cfg.AutoAssignOrg,
CSPReportOnlyEnabled: cfg.CSPReportOnlyEnabled,
DisableLoginForm: cfg.DisableLoginForm,
DisableUserSignUp: !cfg.AllowUserSignUp,
GoogleAnalytics4Id: cfg.GoogleAnalytics4ID,
GoogleAnalytics4SendManualPageViews: cfg.GoogleAnalytics4SendManualPageViews,
GoogleAnalyticsId: cfg.GoogleAnalyticsID,
GrafanaJavascriptAgent: cfg.GrafanaJavascriptAgent,
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme,
JwtHeaderName: cfg.JWTAuth.HeaderName,
JwtUrlLogin: cfg.JWTAuth.URLLogin,
LdapEnabled: cfg.LDAPAuthEnabled,
LoginHint: cfg.LoginHint,
PasswordHint: cfg.PasswordHint,
ReportingStaticContext: cfg.ReportingStaticContext,
RudderstackConfigUrl: cfg.RudderstackConfigURL,
RudderstackDataPlaneUrl: cfg.RudderstackDataPlaneURL,
RudderstackIntegrationsUrl: cfg.RudderstackIntegrationsURL,
RudderstackSdkUrl: cfg.RudderstackSDKURL,
RudderstackWriteKey: cfg.RudderstackWriteKey,
TrustedTypesDefaultPolicyEnabled: (cfg.CSPEnabled && strings.Contains(cfg.CSPTemplate, "require-trusted-types-for")) || (cfg.CSPReportOnlyEnabled && strings.Contains(cfg.CSPReportOnlyTemplate, "require-trusted-types-for")),
VerifyEmailEnabled: cfg.VerifyEmailEnabled,
BuildInfo: getBuildInfo(license, cfg),
AnalyticsConsoleReporting: cfg.FrontendAnalyticsConsoleReporting,
AnonymousEnabled: cfg.Anonymous.Enabled,
ApplicationInsightsConnectionString: cfg.ApplicationInsightsConnectionString,
ApplicationInsightsEndpointUrl: cfg.ApplicationInsightsEndpointUrl,
ApplicationInsightsAutoRouteTracking: cfg.ApplicationInsightsAutoRouteTracking,
AuthProxyEnabled: cfg.AuthProxy.Enabled,
AutoAssignOrg: cfg.AutoAssignOrg,
CSPReportOnlyEnabled: cfg.CSPReportOnlyEnabled,
DisableLoginForm: cfg.DisableLoginForm,
DisableUserSignUp: !cfg.AllowUserSignUp,
GoogleAnalytics4Id: cfg.GoogleAnalytics4ID,
GoogleAnalytics4SendManualPageViews: cfg.GoogleAnalytics4SendManualPageViews,
GoogleAnalyticsId: cfg.GoogleAnalyticsID,
GrafanaJavascriptAgent: cfg.GrafanaJavascriptAgent,
Http2Enabled: cfg.Protocol == setting.HTTP2Scheme,
JwtHeaderName: cfg.JWTAuth.HeaderName,
JwtUrlLogin: cfg.JWTAuth.URLLogin,
LdapEnabled: cfg.LDAPAuthEnabled,
LoginHint: cfg.LoginHint,
PasswordHint: cfg.PasswordHint,
ReportingStaticContext: cfg.ReportingStaticContext,
RudderstackConfigUrl: cfg.RudderstackConfigURL,
RudderstackDataPlaneUrl: cfg.RudderstackDataPlaneURL,
RudderstackIntegrationsUrl: cfg.RudderstackIntegrationsURL,
RudderstackSdkUrl: cfg.RudderstackSDKURL,
RudderstackWriteKey: cfg.RudderstackWriteKey,
TrustedTypesDefaultPolicyEnabled: (cfg.CSPEnabled && strings.Contains(cfg.CSPTemplate, "require-trusted-types-for")) || (cfg.CSPReportOnlyEnabled && strings.Contains(cfg.CSPReportOnlyTemplate, "require-trusted-types-for")),
VerifyEmailEnabled: cfg.VerifyEmailEnabled,
BuildInfo: getBuildInfo(license, cfg),
}
return &IndexProvider{
+10 -8
View File
@@ -390,14 +390,15 @@ type Cfg struct {
LocalFileSystemAvailable bool
// Analytics
CheckForGrafanaUpdates bool
CheckForPluginUpdates bool
ReportingDistributor string
ReportingEnabled bool
ApplicationInsightsConnectionString string
ApplicationInsightsEndpointUrl string
FeedbackLinksEnabled bool
ReportingStaticContext map[string]string
CheckForGrafanaUpdates bool
CheckForPluginUpdates bool
ReportingDistributor string
ReportingEnabled bool
ApplicationInsightsConnectionString string
ApplicationInsightsEndpointUrl string
ApplicationInsightsAutoRouteTracking bool
FeedbackLinksEnabled bool
ReportingStaticContext map[string]string
// Frontend analytics
GoogleAnalyticsID string
@@ -1273,6 +1274,7 @@ func (cfg *Cfg) parseINIFile(iniFile *ini.File) error {
cfg.ApplicationInsightsConnectionString = analytics.Key("application_insights_connection_string").String()
cfg.ApplicationInsightsEndpointUrl = analytics.Key("application_insights_endpoint_url").String()
cfg.ApplicationInsightsAutoRouteTracking = analytics.Key("application_insights_connection_string").MustBool(true)
cfg.FeedbackLinksEnabled = analytics.Key("feedback_links_enabled").MustBool(true)
// parse reporting static context string of key=value, key=value pairs into an object
@@ -23,6 +23,7 @@ declare global {
export interface ApplicationInsightsBackendOptions {
connectionString: string;
endpointUrl?: string;
autoRouteTracking?: boolean;
}
export class ApplicationInsightsBackend implements EchoBackend<PageviewEchoEvent, ApplicationInsightsBackendOptions> {
@@ -33,6 +34,7 @@ export class ApplicationInsightsBackend implements EchoBackend<PageviewEchoEvent
config: {
connectionString: options.connectionString,
endpointUrl: options.endpointUrl,
enableAutoRouteTracking: options.autoRouteTracking,
},
};
+1
View File
@@ -170,6 +170,7 @@ async function initAzureAppInsightsBackend() {
new ApplicationInsightsBackend({
connectionString: config.applicationInsightsConnectionString,
endpointUrl: config.applicationInsightsEndpointUrl,
autoRouteTracking: config.applicationInsightsAutoRouteTracking,
})
);
}