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

Extend csplib to add Azure SQL Database #1278

Merged
merged 4 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions csp-mixin/config.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
{
blobstore: (import './signals/blobstore.libsonnet')(this),
azureelasticpool: (import './signals/azureelasticpool.libsonnet')(this),
azuresqldb: (import './signals/azuresqldb.libsonnet')(this),
},
blobStorage: {
enableAvailability: false,
Expand Down
16 changes: 16 additions & 0 deletions csp-mixin/dashboards.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,21 @@ local commonlib = import 'common-lib/common/main.libsonnet';
csplib.grafana.rows.aep_resources
)
),

[csplib.config.uid + '-sqldb.json']:
local variables = csplib.signals.azuresqldb.getVariablesMultiChoice();
g.dashboard.new(csplib.config.dashboardNamePrefix + 'SQL database')
+ g.dashboard.withUid(csplib.config.uid + '-sqldb')
+ g.dashboard.withTags(csplib.config.dashboardTags)
+ g.dashboard.withTimezone(csplib.config.dashboardTimezone)
+ g.dashboard.withRefresh(csplib.config.dashboardRefresh)
+ g.dashboard.timepicker.withTimeOptions(csplib.config.dashboardPeriod)
+ g.dashboard.withVariables(variables)
+ g.dashboard.withPanels(
g.util.grid.wrapPanels(
csplib.grafana.rows.asql_connections +
csplib.grafana.rows.asql_resources
)
),
} else {},
}
1 change: 1 addition & 0 deletions csp-mixin/main.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ local commonlib = import 'common-lib/common/main.libsonnet';
{
blobstore: commonlib.signals.unmarshallJsonMulti(this.config.signals.blobstore, type=this.config.metricsSource),
azureelasticpool: commonlib.signals.unmarshallJsonMulti(this.config.signals.azureelasticpool, type=this.config.metricsSource),
azuresqldb: commonlib.signals.unmarshallJsonMulti(this.config.signals.azuresqldb, type=this.config.metricsSource),
},
grafana: {
panels: (import './panels.libsonnet').new(this),
Expand Down
115 changes: 115 additions & 0 deletions csp-mixin/panels.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -268,5 +268,120 @@ local commonlib = import 'common-lib/common/main.libsonnet';
this.signals.azureelasticpool.session.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize()
+ g.panel.timeSeries.fieldConfig.defaults.custom.stacking.withMode('normal'),

// Azure SQL Database
_asql_tableCommon()::
g.panel.table.queryOptions.withTransformations([
g.panel.table.queryOptions.transformation.withId('filterFieldsByName')
+ g.panel.table.queryOptions.transformation.withOptions({
include: {
pattern: 'database.*|Value.*',
},
}),
g.panel.table.queryOptions.transformation.withId('joinByField')
+ g.panel.table.queryOptions.transformation.withOptions({
byField: 'database',
mode: 'outer',
}),
])
+ g.panel.table.standardOptions.withOverrides([
{
matcher: {
id: 'byName',
options: 'database',
},
properties: [
{
id: 'displayName',
value: 'Database',
},
],
},
{
matcher: {
id: 'byName',
options: 'Value #Used',
},
properties: [
{
id: 'displayName',
value: 'Used',
},
],
},
{
matcher: {
id: 'byName',
options: 'Value #Percent of limit',
},
properties: [
{
id: 'displayName',
value: 'Percent of limit',
},
],
},
{
matcher: {
id: 'byName',
options: 'Value #Limit',
},
properties: [
{
id: 'displayName',
value: 'Limit',
},
],
},
]),
asql_conns:
this.signals.azuresqldb.successfulConns.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize(),

asql_deadlocks:
this.signals.azuresqldb.deadlocks.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize(),

asql_sessions:
this.signals.azuresqldb.sessions.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize(),

asql_cpu:
this.signals.azuresqldb.cpuPercent.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize()
+ this.signals.azuresqldb.vCoreCpuPercent.asPanelMixin(),

asql_storagebytes:
this.signals.azuresqldb.storageBytes.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize()
+ g.panel.timeSeries.fieldConfig.defaults.custom.stacking.withMode('normal'),

asql_storagepercent:
this.signals.azuresqldb.storagePercent.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize(),

asql_dtuts:
this.signals.azuresqldb.dtuUsed.asTimeSeries()
+ commonlib.panels.generic.timeSeries.base.stylize(),

asql_dtutbl:
this.signals.azuresqldb.dtuUsed.common
+ commonlib.panels.generic.table.base.new(
'DTU utilization and limits by database',
[
this.signals.azuresqldb.dtuUsed.asTarget()
+ g.query.prometheus.withFormat('table')
+ g.query.prometheus.withInstant(true),

this.signals.azuresqldb.dtuPercent.asTarget()
+ g.query.prometheus.withFormat('table')
+ g.query.prometheus.withInstant(true),

this.signals.azuresqldb.dtuLimit.asTarget()
+ g.query.prometheus.withFormat('table')
+ g.query.prometheus.withInstant(true),
],
'DTU utilization and limits by database'
) + self._asql_tableCommon(),
Comment on lines +367 to +385
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you could also try to define tables with using asTable() and asTableColumn() now:
#1290

},
}
39 changes: 39 additions & 0 deletions csp-mixin/rows.libsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,44 @@ local g = import './g.libsonnet';
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(6),
],

// Azure SQL Database
asql_connections: [
g.panel.row.new('Connections'),
this.grafana.panels.asql_conns
+ g.panel.timeSeries.gridPos.withW(8)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_deadlocks
+ g.panel.timeSeries.gridPos.withW(8)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_sessions
+ g.panel.timeSeries.gridPos.withW(8)
+ g.panel.timeSeries.gridPos.withH(8),
],

asql_resources: [
g.panel.row.new('Resources'),
this.grafana.panels.asql_cpu
+ g.panel.timeSeries.gridPos.withW(24)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_storagebytes
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_storagepercent
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_dtuts
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8),

this.grafana.panels.asql_dtutbl
+ g.panel.timeSeries.gridPos.withW(12)
+ g.panel.timeSeries.gridPos.withH(8),
],
},
}
139 changes: 139 additions & 0 deletions csp-mixin/signals/azuresqldb.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
local commonlib = import 'common-lib/common/main.libsonnet';
function(this)
{
local s = self,
filteringSelector: this.filteringSelector,
groupLabels: this.groupLabels,
instanceLabels: this.instanceLabels,
aggLevel: 'none',
discoveryMetric: {
azuremonitor: 'azure_microsoft_storage_storageaccounts_blobservices_blobcount_average_count',
},

signals: {
successfulConns: {
name: 'Successful connections by database',
description: 'Count of successful connections by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_connection_successful_total_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

deadlocks: {
name: 'Deadlocks by database',
description: 'Count of deadlocks by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_deadlock_total_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

sessions: {
name: 'Average sessions by database',
description: 'Average number of sessions by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_sessions_count_average_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

cpuPercent: {
name: 'CPU utilization by database',
description: 'Percent of CPU utilization by database. If database uses vCores, the vCore percent utilization is shown',
type: 'gauge',
unit: 'percent',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_cpu_percent_average_percent{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

vCoreCpuPercent: {
name: 'vCore utilization by database',
description: 'Percent of CPU utilization by database. If database uses vCores, the vCore percent utilization is shown',
type: 'gauge',
unit: 'percent',
sources: {
azuremonitor: {
expr: '100 * (label_replace(azure_microsoft_sql_servers_databases_cpu_used_average_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)") / label_replace(azure_microsoft_sql_servers_databases_cpu_limit_average_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)"))',
legendCustomTemplate: '{{database}} vCore',
},
},
},
Copy link
Contributor

@v-zhuravlev v-zhuravlev Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type=gauge and aggLevel=none is equivalent of type=raw. Right now it would be just fine, however, changing aggLevel to instance/group later on would break this signal, as 100 * would be applied in the wrong place.
Best to change type to raw, or move 100 * to exprWrappers:
https://github.com/grafana/jsonnet-libs/tree/master/common-lib/common/signal#configuration-options

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh excellent. Thank you for this, I'll add it to the exprWrappers.


storageBytes: {
name: 'Storage utilization by database',
description: 'Bytes of storage by database',
type: 'gauge',
unit: 'bytes',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_storage_maximum_bytes{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

storagePercent: {
name: 'Storage % of limit by database',
description: 'Percent used of storage limitby database',
type: 'gauge',
unit: 'percent',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_storage_percent_maximum_percent{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

dtuUsed: {
name: 'Used',
description: 'Average number of DTUs utilized by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_dtu_used_average_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

dtuPercent: {
name: 'Percent of limit',
description: 'Average percent of DTU limit utilized by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_dtu_consumption_percent_average_percent{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},

dtuLimit: {
name: 'Limit',
description: 'DTU limit by database',
type: 'gauge',
sources: {
azuremonitor: {
expr: 'label_replace(azure_microsoft_sql_servers_databases_dtu_limit_average_count{%(queriesSelector)s}, "database", "$1", "resourceID", ".+/(.*)")',
legendCustomTemplate: '{{database}}',
},
},
},
},

}
Loading