Improve MSSQL (Windows.plugin Part II) (#20141)
thiagoftsm committed
May 2, 2025 at 17:25 UTC
4b63e6cdad29f3873e03e2e448084bbdf30b9c58
4 files changed
+725
-267
src/collectors/windows.plugin/README.md
+105
-99
@@ -1,19 +1,16 @@
1
# Windows.plugin
2
3
-This internal plugin is only available for Microsoft Windows operating systems.
3
+This internal plugin is exclusively available for Microsoft Windows operating systems.
4
5
-## The Collector
5
+## Overview
6
7
-This plugin primarily collects metrics from Microsoft Windows [Performance Counters](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-what-s-new). All detected metrics are automatically displayed without requiring additional configuration.
8
-=======
9
-Most of the metrics collected by this plugin originate from Microsoft Windows
10
-[Performance Counters](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-what-s-new).
7
+The Windows plugin primarily collects metrics from Microsoft Windows [Performance Counters](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-what-s-new). All detected metrics are automatically displayed in the Netdata dashboard without requiring additional configuration.
8
12
-These metrics are always displayed when detected, requiring no additional configuration.
9
+## Default Configuration
10
14
-By default, all collector threads are enabled except for `PerflibThermalZone` and `PerflibServices`. You can enable these or disable others by modifying options in the `[plugin:windows]` section of the configuration file.
11
+By default, all collector threads are enabled except for `PerflibThermalZone` and `PerflibServices`. You can enable these disabled collectors or disable any of the currently active ones by modifying the `[plugin:windows]` section in your configuration file.
12
16
-To change a setting, remove the comment symbol (`#`) from the beginning of the line and set the value to either `yes` or `no`:
13
+To change a setting, remove the comment symbol (`#`) from the beginning of the line and set the value to either `yes` or `no`.
14
15
```text
16
[plugin:windows]
@@ -36,155 +33,164 @@ To change a setting, remove the comment symbol (`#`) from the beginning of the l
33
# PerflibADFS = yes
34
```
35
39
-## Configuration
36
+## Microsoft SQL Server Integration
37
41
-To collect certain metrics for [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server),
42
-Netdata needs access to internal server data. To collect this data, you need to configure both your server and Netdata.
38
+To collect metrics from [Microsoft SQL Server](https://www.microsoft.com/en-us/sql-server), Netdata needs access to internal server data. This requires configuration on both the Windows system and Netdata sides.
39
44
-### Windows Defender Firewall with Advanced Security
40
+## Configuring
41
46
-To connect to your SQL Server, Netdata uses TCP port 1433 (or any other configured port).
47
-This port is typically blocked by Windows Defender, so you must allow access before proceeding:
42
+### Step 1: Configure Windows Defender Firewall
43
49
-1. Open `Windows Defender Firewall with Advanced Security` as an Adminstrator.
50
-2. Right-click `Inbound Rules` and select `New Rule...`.
51
-3. Select `Port`, then click `Next`.
52
-4. Choose `TCP`, then enter `1433` in the `Specific local ports:`. Click `Next`.
53
-5. Select an appropriate action based on your network policy. For example, `Allow the connection`.
54
- Click `Next`.
55
-6. Choose where the rule will be applied (Domain, Private, or Public).
56
-7. Finally, provide a `Name` and an optional `Description` for the new rule,
57
- then click `Finish`.
44
+Netdata connects to SQL Server using TCP port 1433 (or your custom-configured port). You'll need to create a firewall rule to allow this connection:
45
59
-You can use the same rule to allow connections to other instances. To do this,
60
-specify the ports for each instance in the `Port` field separated by commas.
46
+1. Open `Windows Defender Firewall with Advanced Security` as an Administrator
47
+2. Right-click `Inbound Rules` and select `New Rule...`
48
+3. Select `Port`, then click `Next`
49
+4. Choose `TCP`, enter `1433` in the `Specific local ports:` field, then click `Next`
50
+5. Select an appropriate action (typically `Allow the connection`), then click `Next`
51
+6. Choose where the rule applies (Domain, Private, or Public networks), then click `Next`
52
+7. Provide a name and optional description for the rule, then click `Finish`
53
62
-### Microsoft SQL Server (Configuration)
54
+For multiple SQL Server instances, you can specify multiple ports in the same rule by separating them with commas.
55
64
-After enabling access through the firewall, you will need to configure your SQL Server instance to accept TCP
65
-connections:
56
+### Step 2: Configure SQL Server Network Settings
57
67
-1. Open `SQL Server Configuration Manager`.
68
-2. Expand `SQL Server Network Configuration`.
69
-3. In the console panel, select `Protocols for <instance name>.`.
70
-4. In the details panel, double-click the `TCP` protocol, and set `Yes` for `Enabled`.
71
-5. Go to the `IP Address` tab, locate the section labeled`IPAII`.
72
- - Remove any value from the `TCP Dynamic Ports` field.
73
- - Enter a value in the `TCP Port` field. By default, SQL Server uses `1433`.
74
-6. Finally, select `SQL Server Services`, and restart your SQL Server instance.
58
+Enable SQL Server to accept TCP connections:
59
76
-You need to apply this configuration to every instance.
60
+1. Open `SQL Server Configuration Manager`
61
+2. Expand `SQL Server Network Configuration`
62
+3. Select `Protocols for <instance name>` in the console panel
63
+4. Double-click the `TCP` protocol in the details panel and set `Enabled` to `Yes`
64
+5. Go to the `IP Address` tab and locate the `IPAII` section:
65
+ - Clear any value from the `TCP Dynamic Ports` field
66
+ - Enter a port number in the `TCP Port` field (default is `1433`)
67
+6. Select `SQL Server Services` and restart your SQL Server instance
68
78
-### Microsoft SQL Server (User)
69
+These steps must be performed for each SQL Server instance you want to monitor.
70
80
-If you want to allow connections using SQL Server authentication, you must modify the server configuration:
71
+### Step 3: Configure SQL Server Authentication
72
82
-1. Open `Microsoft Server Management Studio`.
83
-2. Right-click your server, and select `Properties`.
84
-3. In the left panel, select `Security`.
85
-4. Under `Server authentication`, choose `SQL Server and Windows Authentication mode`.
86
-5. Click `OK`.
87
-6. Finally, right-click your server, and select`Restart`.
73
+If you're using SQL Server authentication (rather than Windows authentication):
74
89
-After that, you need to create a user with the `VIEW SERVER STATE` permission to collect data from the server.
90
-Once the user is created, it must also be granted access to the databases.
75
+1. Open `Microsoft Server Management Studio`
76
+2. Right-click your server and select `Properties`
77
+3. Select `Security` in the left panel
78
+4. Choose `SQL Server and Windows Authentication mode` under `Server authentication`
79
+5. Click `OK`
80
+6. Right-click your server and select `Restart`
81
+
82
+### Step 4: Create a Monitoring User
83
+
84
+Create an SQL Server user with the necessary permissions to collect monitoring data:
85
86
```tsql
87
USE master;
94
-CREATE LOGIN netdata_user WITH PASSWORD = 'netdata';
88
+CREATE LOGIN netdata_user WITH PASSWORD = '1ReallyStrongPasswordShouldBeInsertedHere';
89
CREATE USER netdata_user FOR LOGIN netdata_user;
90
GRANT CONNECT SQL TO netdata_user;
91
GRANT VIEW SERVER STATE TO netdata_user;
92
GO
93
```
94
101
-In addition to creating the user, you must enable the
102
-[query store](https://learn.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store?view=sql-server-ver16),
103
-on each database you wish to monitor.
95
+Additionally, enable the [Query Store](https://learn.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store?view=sql-server-ver16) on each database you want to monitor:
96
97
```tsql
98
DECLARE @dbname NVARCHAR(max)
107
-DECLARE nd_user_cursor CURSOR FOR SELECT name FROM master.dbo.sysdatabases WHERE NAME NOT IN ('master','msdb','tempdb','model')
99
+DECLARE nd_user_cursor CURSOR FOR SELECT name
100
+ FROM master.dbo.sysdatabases
101
+ WHERE name NOT IN ('master', 'tempdb')
102
103
OPEN nd_user_cursor
110
-FETCH NEXT FROM nd_user_cursor INTO @dbname WHILE @@FETCH_STATUS = 0
111
-BEGIN
104
+FETCH NEXT FROM nd_user_cursor INTO @dbname
105
+WHILE @@FETCH_STATUS = 0
106
+ BEGIN
107
EXECUTE ("USE "+ @dbname+"; CREATE USER netdata_user FOR LOGIN netdata_user; ALTER DATABASE "+@dbname+" SET QUERY_STORE = ON ( QUERY_CAPTURE_MODE = ALL, DATA_FLUSH_INTERVAL_SECONDS = 900 )");
108
FETCH next FROM nd_user_cursor INTO @dbname;
114
-END
109
+ END
110
CLOSE nd_user_cursor
111
DEALLOCATE nd_user_cursor
112
GO
113
```
114
120
-You need to apply this configuration to every instance.
115
+Apply this configuration to each SQL Server instance you wish to monitor.
116
122
-### Netdata Configuration
117
+### Step 5: Configure Netdata
118
124
-Now that the user has been created inside your server, update `netdata.conf` by adding the following section:
119
+Add the SQL Server connection details to your `netdata.conf` file:
120
126
-```text
121
+```
122
[plugin:windows:PerflibMSSQL]
123
driver = SQL Server
124
server = 127.0.0.1\\Dev, 1433
125
#address = [protocol:]Address[,port |\pipe\pipename]
126
uid = netdata_user
132
- pwd = AReallyStrongPasswordShouldBeInsertedHere
127
+ pwd = 1ReallyStrongPasswordShouldBeInsertedHere
128
# additional instances = 0
129
#windows authentication = no
130
```
131
137
-In next table, we give a short description about them:
138
-
139
-| Option | Description |
140
-|--------------------------|-----------------------------------------------------------------------------------|
141
-|`driver` | ODBC driver used to connect to the MSSQL server. |
142
-|`server` | Server address or instance name to connect to. |
143
-|`address` | Similar to `server`. You can also use named pipes if your server supports them. |
144
-|`uid` | User identifier (`uid`) created on your server. |
145
-|`pwd` | Password for the specified user. |
146
-|`additional instances` | Number of additional MSSQL instances to monitor. |
147
-|`windows authentications` | Use Windows credentials to connect to the MSSQL server. |
132
+Configuration options:
133
149
-For additional information on how to set these parameters, refer to the
150
-[Microsoft Official Documentation](https://learn.microsoft.com/en-us/sql/relational-databases/native-client/applications/using-connection-string-keywords-with-sql-server-native-client?view=sql-server-ver15&viewFallbackFrom=sql-server-ver16)
134
+| Option | Description |
135
+|--------------------------|------------------------------------------------------------------------------|
136
+| `driver` | ODBC driver used to connect to the SQL Server |
137
+| `server` | Server address or instance name |
138
+| `address` | Alternative to `server`; supports named pipes if the server supports them |
139
+| `uid` | SQL Server user identifier |
140
+| `pwd` | Password for the specified user |
141
+| `additional instances` | Number of additional SQL Server instances to monitor |
142
+| `windows authentication` | Set to `yes` to use Windows credentials instead of SQL Server authentication |
143
152
-#### Additional Instance
144
+For more information on connection parameters, see the [Microsoft Official Documentation](https://learn.microsoft.com/en-us/sql/relational-databases/native-client/applications/using-connection-string-keywords-with-sql-server-native-client?view=sql-server-ver15&viewFallbackFrom=sql-server-ver16).
145
154
-Microsoft SQL Server can host multiple instances. To connect to them, you need to create additional sections in your
155
-`netdata.conf` file, specifying their respective connection options.
146
+## Monitoring Multiple SQL Server Instances
147
157
-Let’s suppose you have an additional instance named `Production`. To enable Netdata to monitor both the `Production`
158
-and `Dev` instances, you’ll need to add the following configuration section:
148
+SQL Server can host multiple instances on the same machine. To monitor additional instances:
149
160
-```text
161
-[plugin:windows:PerflibMSSQL1]
150
+1. Update the main section to specify the number of additional instances:
151
+ ```text
152
+ [plugin:windows:PerflibMSSQL]
153
+ additional instances = 1
154
+ ```
155
+2. Add a new configuration section for each additional instance, using sequential numbering:
156
+ ```text
157
+ [plugin:windows:PerflibMSSQL1]
158
driver = SQL Server
159
server = 127.0.0.1\\Production, 1434
160
uid = netdata_user
165
- pwd = AnotherReallyStrongPasswordShouldBeInsertedHere
166
-```
161
+ pwd = AnotherReallyStrongPasswordShouldBeInsertedHere2$
162
+ ```
163
168
-You must also update the main section to indicate how many additional instances you want to monitor:
164
+Each additional instance section must follow the naming pattern `plugin:windows:PerflibMSSQL` with a sequential number from 1 to 65535.
165
170
-```text
171
-[plugin:windows:PerflibMSSQL]
172
- additional instances = 1
173
-```
166
+## Troubleshooting Common Issues
167
+
168
+### Data source name is not found and no default driver
169
+
170
+This error occurs when the specified ODBC driver is incorrect. To check available drivers:
171
+
172
+1. Open `ODBC Data Sources`
173
+2. Go to the `Drivers` tab
174
+3. Look for the correct name of the `ODBC` or SQL `Server driver`
175
175
-Each additional instance section must follow the naming pattern `plugin:windows:PerflibMSSQL`, with a sequential number
176
-from 1 to 65535, based on the number of instances you want to monitor.
176
+### Database Metrics Not Visible
177
178
-### Errors
178
+If a database isn't appearing on the Netdata dashboard, statistics collection might not be enabled:
179
180
-When configuring Netdata to access SQL Server, some errors may occur. You can check your configuration using the
181
-Microsoft Event Viewer by looking for entries that begin with `MSSQL server error using the handle`.
180
+1. Open `SQL Server Configuration Manager`
181
+2. Right-click the database and select `Properties`
182
+3. Select `Options` in the left pane
183
+4. Set `Auto Create Statistics` to `True`
184
+
185
+### Login Failed
186
+
187
+If authentication fails, check the SQL Server error log at:
188
+
189
+```
190
+C:\Program Files\Microsoft SQL Server\VERSION\MSSQL\Log\ERRORLOG
191
+```
192
183
-#### Data source name not found and no default driver
193
+Where `VERSION` corresponds to your SQL Server version.
194
185
-This error occurs when the driver is not specified correctly. You can check the available drivers by following
186
-these steps:
195
+You can also check Windows Event Viewer for entries beginning with `MSSQL server error using the handle`.
196
188
-- Access `ODBC Data Sources`.
189
-- Go to `Drivers` tab.
190
-- Look for `Name` of the `ODBC` or `SQL Server` driver .
src/collectors/windows.plugin/metadata.yaml
+34
-4
@@ -1751,8 +1751,8 @@ modules:
1751
chart_type: line
1752
dimensions:
1753
- name: benefit
1754
- - name: mssql.instance_locks_deadlocks
1755
- description: Lock requests that resulted in deadlock
1754
+ - name: mssql.instance_resource_deadlocks
1755
+ description: Active lock requests that resulted in deadlock per resource
1756
unit: deadlocks/s
1757
chart_type: line
1758
dimensions:
@@ -1770,8 +1770,8 @@ modules:
1770
- name: rid
1771
- name: row_group
1772
- name: xact
1773
- - name: mssql.instance_locks_lock_wait
1774
- description: Lock requests that required the caller to wait
1773
+ - name: mssql.instance_resource_lock_wait
1774
+ description: Active lock requests that required the caller to wait
1775
unit: locks/s
1776
chart_type: line
1777
dimensions:
@@ -1821,6 +1821,30 @@ modules:
1821
chart_type: line
1822
dimensions:
1823
- name: write
1824
+ - name: mssql.database_lockwait
1825
+ description: Lock requests that required the caller to wait.
1826
+ unit: locks/s
1827
+ chart_type: line
1828
+ dimensions:
1829
+ - name: lock
1830
+ - name: mssql.database_deadlocks
1831
+ description: Lock requests that resulted in deadlock.
1832
+ unit: deadlocks/s
1833
+ chart_type: line
1834
+ dimensions:
1835
+ - name: deadlocks
1836
+ - name: mssql.database_lock_timeouts
1837
+ description: Lock that timed out.
1838
+ unit: timeouts/s
1839
+ chart_type: line
1840
+ dimensions:
1841
+ - name: timeouts
1842
+ - name: mssql.database_lock_requests
1843
+ description: Number of new locks and lock conversions requested.
1844
+ unit: requests/s
1845
+ chart_type: line
1846
+ dimensions:
1847
+ - name: requests
1848
- name: mssql.database_backup_restore_operations
1849
description: Backup IO per database
1850
unit: operations/s
@@ -1839,6 +1863,12 @@ modules:
1863
chart_type: line
1864
dimensions:
1865
- name: flushed
1866
+ - name: mssql.database_data_files_size
1867
+ description: Current database size
1868
+ unit: bytes
1869
+ chart_type: line
1870
+ dimensions:
1871
+ - name: size
1872
- meta:
1873
plugin_name: windows.plugin
1874
module_name: PerflibNetFramework
src/collectors/windows.plugin/perflib-mssql.c
+580
-163
@@ -9,10 +9,11 @@
9
10
#define MEGA_FACTOR (1048576) // 1024 * 1024
11
// https://learn.microsoft.com/en-us/sql/sql-server/install/instance-configuration?view=sql-server-ver16
12
-#define NETDATA_MAX_INSTANCE_NAME 32
13
-#define NETDATA_MAX_INSTANCE_OBJECT 128
12
+#define NETDATA_MAX_INSTANCE_NAME (32)
13
+#define NETDATA_MAX_INSTANCE_OBJECT (128)
14
// https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms191240(v=sql.105)#sysname
15
-#define SQLSERVER_MAX_NAME_LENGTH (128)
15
+#define SQLSERVER_MAX_NAME_LENGTH NETDATA_MAX_INSTANCE_OBJECT
16
+#define NETDATA_MSSQL_NEXT_TRY (60)
17
18
BOOL is_sqlexpress = FALSE;
19
@@ -29,7 +30,12 @@ struct netdata_mssql_conn {
30
31
SQLHENV netdataSQLEnv;
32
SQLHDBC netdataSQLHDBc;
33
+
34
+ SQLHSTMT checkPermSTMT;
35
+ SQLHSTMT databaseListSTMT;
36
SQLHSTMT dataFileSizeSTMT;
37
+ SQLHSTMT dbTransactionSTMT;
38
+ SQLHSTMT dbLocksSTMT;
39
40
BOOL is_connected;
41
};
@@ -133,6 +139,8 @@ struct mssql_instance {
139
};
140
141
struct mssql_lock_instance {
142
+ struct mssql_instance *parent;
143
+
144
char *resourceID;
145
146
COUNTER_DATA lockWait;
@@ -142,20 +150,11 @@ struct mssql_lock_instance {
150
RRDDIM *rd_deadLocks;
151
};
152
145
-enum db_instance_idx {
146
- NETDATA_MSSQL_ENUM_MDI_IDX_ACTIVE_TRANSACTIONS,
147
- NETDATA_MSSQL_ENUM_MDI_IDX_BACKUP_RESTORE_OP,
148
- NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHED,
149
- NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHES,
150
- NETDATA_MSSQL_ENUM_MDI_IDX_TRANSACTIONS,
151
- NETDATA_MSSQL_ENUM_MDI_IDX_WRITE_TRANSACTIONS,
152
-
153
- NETDATA_MSSQL_ENUM_MDI_IDX_END
154
-};
155
-
153
struct mssql_db_instance {
154
struct mssql_instance *parent;
155
156
+ bool collecting_data;
157
+
158
RRDSET *st_db_data_file_size;
159
RRDSET *st_db_active_transactions;
160
RRDSET *st_db_backup_restore_operations;
@@ -163,6 +162,10 @@ struct mssql_db_instance {
162
RRDSET *st_db_log_flushes;
163
RRDSET *st_db_transactions;
164
RRDSET *st_db_write_transactions;
165
+ RRDSET *st_db_lockwait;
166
+ RRDSET *st_db_deadlock;
167
+ RRDSET *st_lock_timeouts;
168
+ RRDSET *st_lock_requests;
169
170
RRDDIM *rd_db_data_file_size;
171
RRDDIM *rd_db_active_transactions;
@@ -171,15 +174,25 @@ struct mssql_db_instance {
174
RRDDIM *rd_db_log_flushes;
175
RRDDIM *rd_db_transactions;
176
RRDDIM *rd_db_write_transactions;
177
+ RRDDIM *rd_db_lockwait;
178
+ RRDDIM *rd_db_deadlock;
179
+ RRDDIM *rd_lock_timeouts;
180
+ RRDDIM *rd_lock_requests;
181
+
182
+ COUNTER_DATA MSSQLDatabaseDataFileSize;
183
184
COUNTER_DATA MSSQLDatabaseActiveTransactions;
185
COUNTER_DATA MSSQLDatabaseBackupRestoreOperations;
177
- COUNTER_DATA MSSQLDatabaseDataFileSize;
186
COUNTER_DATA MSSQLDatabaseLogFlushed;
187
COUNTER_DATA MSSQLDatabaseLogFlushes;
188
COUNTER_DATA MSSQLDatabaseTransactions;
189
COUNTER_DATA MSSQLDatabaseWriteTransactions;
190
191
+ COUNTER_DATA MSSQLDatabaseLockWaitSec;
192
+ COUNTER_DATA MSSQLDatabaseDeadLockSec;
193
+ COUNTER_DATA MSSQLDatabaseLockTimeoutsSec;
194
+ COUNTER_DATA MSSQLDatabaseLockRequestsSec;
195
+
196
uint32_t updated;
197
};
198
@@ -223,17 +236,19 @@ static char *netdata_MSSQL_type_text(uint32_t type)
236
}
237
238
// Connection and SQL
226
-static void netdata_MSSQL_error(uint32_t type, SQLHANDLE handle, enum netdata_mssql_odbc_errors step)
239
+static void netdata_MSSQL_error(uint32_t type, SQLHANDLE handle, enum netdata_mssql_odbc_errors step, char *instance)
240
{
241
SQLCHAR state[1024];
242
SQLCHAR message[1024];
243
if (SQL_SUCCESS == SQLGetDiagRec((short)type, handle, 1, state, NULL, message, 1024, NULL)) {
244
char *str_step = netdata_MSSQL_error_text(step);
245
char *str_type = netdata_MSSQL_type_text(type);
246
+ char *use_instance = (!instance) ? "no instance" : instance;
247
nd_log(
248
NDLS_COLLECTORS,
235
- NDLP_ERR,
236
- "MSSQL server error using the handle %s running %s : %s, %s",
249
+ NDLP_INFO,
250
+ "MSSQL server error on %s using the handle %s running %s : %s, %s",
251
+ use_instance,
252
str_type,
253
str_step,
254
message,
@@ -241,60 +256,336 @@ static void netdata_MSSQL_error(uint32_t type, SQLHANDLE handle, enum netdata_ms
256
}
257
}
258
244
-static ULONGLONG netdata_MSSQL_fill_data_file_size_dict(SQLHSTMT *stmt, SQLCHAR *query)
259
+static inline void netdata_MSSQL_release_results(SQLHSTMT *stmt) {
260
+ SQLFreeStmt(stmt, SQL_CLOSE);
261
+ SQLFreeStmt(stmt, SQL_UNBIND);
262
+ SQLFreeStmt(stmt, SQL_RESET_PARAMS);
263
+}
264
+
265
+static ULONGLONG netdata_MSSQL_fill_long_value(SQLHSTMT *stmt, const char *mask, const char *dbname, char *instance)
266
{
246
- static long db_size = 0;
247
- static SQLLEN col_data_len = 0;
267
+ long db_size = 0;
268
+ SQLLEN col_data_len = 0;
269
+
270
+ SQLCHAR query[512];
271
+ snprintfz((char *)query, 511, mask, dbname);
272
273
SQLRETURN ret;
274
275
ret = SQLExecDirect(stmt, query, SQL_NTS);
276
if (ret != SQL_SUCCESS) {
253
- netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_QUERY);
254
- return 0;
277
+ netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_QUERY, instance);
278
+ return (ULONGLONG)ULONG_LONG_MAX;
279
}
280
281
ret = SQLBindCol(stmt, 1, SQL_C_LONG, &db_size, sizeof(long), &col_data_len);
282
283
if (ret != SQL_SUCCESS) {
260
- netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_PREPARE);
261
- return 0;
284
+ netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_PREPARE, instance);
285
+ return (ULONGLONG)ULONG_LONG_MAX;
286
}
287
288
ret = SQLFetch(stmt);
289
if (ret != SQL_SUCCESS) {
266
- netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_FETCH);
267
- return 0;
290
+ netdata_MSSQL_error(SQL_HANDLE_STMT, stmt, NETDATA_MSSQL_ODBC_FETCH, instance);
291
+ return (ULONGLONG)ULONG_LONG_MAX;
292
}
293
294
+ netdata_MSSQL_release_results(stmt);
295
return (ULONGLONG)(db_size * MEGA_FACTOR);
296
}
297
273
-ULONGLONG netdata_MSSQL_fill_data_file_size(struct netdata_mssql_conn *nmc, char *dbname)
298
+#define NETDATA_QUERY_LIST_DB "SELECT name FROM sys.databases;"
299
+
300
+// https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-files-transact-sql?view=sql-server-ver16
301
+#define NETDATA_QUERY_DATA_FILE_SIZE_MASK "SELECT size * 8/1024 FROM %s.sys.database_files WHERE type = 0;"
302
+
303
+// https://learn.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysprocesses-transact-sql?view=sql-server-ver16
304
+// SQL SERVER BEFORE 2008 DOES NOT HAVE DATA IN THIS TABLE
305
+// https://github.com/influxdata/telegraf/blob/081dfa26e80d8764fb7f9aac5230e81584b62b56/plugins/inputs/sqlserver/sqlqueriesV2.go#L1259
306
+#define NETDATA_QUERY_TRANSACTIONS_MASK \
307
+ "select counter_name, cntr_value from %s.sys.dm_os_performance_counters where instance_name = '%s' and counter_name in ('Active Transactions', 'Transactions/sec', 'Write Transactions/sec', 'Backup/Restore Throughput/sec', 'Log Bytes Flushed/sec', 'Log Flushes/sec', 'Number of Deadlocks/sec', 'Lock Waits/sec', 'Lock Timeouts/sec', 'Lock Requests/sec');"
308
+
309
+#define NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC "Active Transactions"
310
+#define NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC "Transactions/sec"
311
+#define NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC "Write Transactions/sec"
312
+#define NETDATA_MSSQL_BACKUP_RESTORE_METRIC "Backup/Restore Throughput/sec"
313
+#define NETDATA_MSSQL_LOG_FLUSHED_METRIC "Log Bytes Flushed/sec"
314
+#define NETDATA_MSSQL_LOG_FLUSHES_METRIC "Log Flushes/sec"
315
+#define NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC "Number of Deadlocks/sec"
316
+#define NETDATA_MSSQL_LOCK_WAITS_METRIC "Lock Waits/sec"
317
+#define NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC "Lock Timeouts/sec"
318
+#define NETDATA_MSSQL_LOCK_REQUESTS_METRIC "Lock Requests/sec"
319
+
320
+void dict_mssql_fill_transactions(struct mssql_db_instance *mdi, const char *dbname)
321
{
275
- ULONGLONG value = 0;
322
+ char object_name[NETDATA_MAX_INSTANCE_OBJECT + 1];
323
+ long value;
324
+ SQLLEN col_object_len = 0, col_value_len = 0;
325
277
- // We cannot access data for these tables without additional changes.
278
- // They should be blacklisted.
279
- if (!strcmp(dbname, "model") || !!strcmp(dbname, "model_msdb") || !!strcmp(dbname, "model_replicatedmaster") || strcmp(dbname, "mssqlsystemresource"))
280
- return ULONG_LONG_MAX;
326
+ SQLCHAR query[sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
327
+ snprintfz(
328
+ (char *)query,
329
+ sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
330
+ NETDATA_QUERY_TRANSACTIONS_MASK,
331
+ dbname,
332
+ dbname);
333
282
- // https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-files-transact-sql?view=sql-server-ver16
283
- SQLCHAR query[512];
284
- snprintfz((char *)query, 511, "SELECT size * 8/1024 FROM %s.sys.database_files WHERE type = 0;", dbname);
334
+ SQLRETURN ret = SQLExecDirect(mdi->parent->conn.dbTransactionSTMT, (SQLCHAR *)query, SQL_NTS);
335
+ if (ret != SQL_SUCCESS) {
336
+ mdi->collecting_data = false;
337
+ netdata_MSSQL_error(
338
+ SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
339
+ goto endtransactions;
340
+ }
341
286
- value = netdata_MSSQL_fill_data_file_size_dict(nmc->dataFileSizeSTMT, query);
342
+ ret = SQLBindCol(
343
+ mdi->parent->conn.dbTransactionSTMT, 1, SQL_C_CHAR, object_name, sizeof(object_name), &col_object_len);
344
+ if (ret != SQL_SUCCESS) {
345
+ netdata_MSSQL_error(
346
+ SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
347
+ goto endtransactions;
348
+ }
349
288
- SQLFreeStmt(nmc->dataFileSizeSTMT, SQL_CLOSE);
289
- return value;
350
+ ret = SQLBindCol(mdi->parent->conn.dbTransactionSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
351
+ if (ret != SQL_SUCCESS) {
352
+ netdata_MSSQL_error(
353
+ SQL_HANDLE_STMT, mdi->parent->conn.dbTransactionSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
354
+ goto endtransactions;
355
+ }
356
+
357
+ do {
358
+ ret = SQLFetch(mdi->parent->conn.dbTransactionSTMT);
359
+ switch (ret) {
360
+ case SQL_SUCCESS:
361
+ case SQL_SUCCESS_WITH_INFO:
362
+ break;
363
+ case SQL_NO_DATA:
364
+ default:
365
+ goto endtransactions;
366
+ }
367
+
368
+ // We cannot use strcmp, because buffer is filled with spaces instead NULL.
369
+ if (!strncmp(
370
+ object_name,
371
+ NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC,
372
+ sizeof(NETDATA_MSSQL_ACTIVE_TRANSACTIONS_METRIC) - 1))
373
+ mdi->MSSQLDatabaseActiveTransactions.current.Data = (ULONGLONG)value;
374
+ else if (!strncmp(
375
+ object_name,
376
+ NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC,
377
+ sizeof(NETDATA_MSSQL_TRANSACTION_PER_SEC_METRIC) - 1))
378
+ mdi->MSSQLDatabaseTransactions.current.Data = (ULONGLONG)value;
379
+ else if (!strncmp(
380
+ object_name,
381
+ NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC,
382
+ sizeof(NETDATA_MSSQL_WRITE_TRANSACTIONS_METRIC) - 1))
383
+ mdi->MSSQLDatabaseWriteTransactions.current.Data = (ULONGLONG)value;
384
+ else if (!strncmp(
385
+ object_name, NETDATA_MSSQL_BACKUP_RESTORE_METRIC, sizeof(NETDATA_MSSQL_BACKUP_RESTORE_METRIC) - 1))
386
+ mdi->MSSQLDatabaseBackupRestoreOperations.current.Data = (ULONGLONG)value;
387
+ else if (!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHED_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHED_METRIC) - 1))
388
+ mdi->MSSQLDatabaseLogFlushed.current.Data = (ULONGLONG)value;
389
+ else if (!strncmp(object_name, NETDATA_MSSQL_LOG_FLUSHES_METRIC, sizeof(NETDATA_MSSQL_LOG_FLUSHES_METRIC) - 1))
390
+ mdi->MSSQLDatabaseLogFlushes.current.Data = (ULONGLONG)value;
391
+ else if (!strncmp(
392
+ object_name,
393
+ NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC,
394
+ sizeof(NETDATA_MSSQL_NUMBER_DEADLOCKS_METRIC) - 1))
395
+ mdi->MSSQLDatabaseDeadLockSec.current.Data = (ULONGLONG)value;
396
+ else if (!strncmp(object_name, NETDATA_MSSQL_LOCK_WAITS_METRIC, sizeof(NETDATA_MSSQL_LOCK_WAITS_METRIC) - 1))
397
+ mdi->MSSQLDatabaseLockWaitSec.current.Data = (ULONGLONG)value;
398
+ else if (!strncmp(
399
+ object_name, NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_TIMEOUTS_METRIC) - 1))
400
+ mdi->MSSQLDatabaseLockTimeoutsSec.current.Data = (ULONGLONG)value;
401
+ else if (!strncmp(
402
+ object_name, NETDATA_MSSQL_LOCK_REQUESTS_METRIC, sizeof(NETDATA_MSSQL_LOCK_REQUESTS_METRIC) - 1))
403
+ mdi->MSSQLDatabaseLockRequestsSec.current.Data = (ULONGLONG)value;
404
+
405
+ } while (true);
406
+
407
+endtransactions:
408
+ netdata_MSSQL_release_results(mdi->parent->conn.dbTransactionSTMT);
409
}
410
292
-int dict_mssql_databases_run_query(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
411
+// https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-tran-locks-transact-sql?view=sql-server-ver16
412
+#define NETDATA_QUERY_LOCKS_MASK \
413
+ "SELECT resource_type, count(*) FROM %s.sys.dm_tran_locks WHERE DB_NAME(resource_database_id) = '%s' group by resource_type;"
414
+void dict_mssql_fill_locks(struct mssql_db_instance *mdi, const char *dbname)
415
+{
416
+#define NETDATA_MSSQL_MAX_RESOURCE_TYPE (60)
417
+ char resource_type[NETDATA_MSSQL_MAX_RESOURCE_TYPE + 1];
418
+ long value;
419
+ SQLLEN col_object_len = 0, col_value_len = 0;
420
+
421
+ SQLCHAR query[sizeof(NETDATA_QUERY_LOCKS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT + 1];
422
+ snprintfz(
423
+ (char *)query,
424
+ sizeof(NETDATA_QUERY_TRANSACTIONS_MASK) + 2 * NETDATA_MAX_INSTANCE_OBJECT,
425
+ NETDATA_QUERY_LOCKS_MASK,
426
+ dbname,
427
+ dbname);
428
+
429
+ SQLRETURN ret = SQLExecDirect(mdi->parent->conn.dbLocksSTMT, (SQLCHAR *)query, SQL_NTS);
430
+ if (ret != SQL_SUCCESS) {
431
+ mdi->collecting_data = false;
432
+ netdata_MSSQL_error(
433
+ SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_QUERY, mdi->parent->instanceID);
434
+ goto endlocks;
435
+ }
436
+
437
+ ret =
438
+ SQLBindCol(mdi->parent->conn.dbLocksSTMT, 1, SQL_C_CHAR, resource_type, sizeof(resource_type), &col_object_len);
439
+ if (ret != SQL_SUCCESS) {
440
+ netdata_MSSQL_error(
441
+ SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
442
+ goto endlocks;
443
+ }
444
+
445
+ ret = SQLBindCol(mdi->parent->conn.dbLocksSTMT, 2, SQL_C_LONG, &value, sizeof(value), &col_value_len);
446
+ if (ret != SQL_SUCCESS) {
447
+ netdata_MSSQL_error(
448
+ SQL_HANDLE_STMT, mdi->parent->conn.dbLocksSTMT, NETDATA_MSSQL_ODBC_PREPARE, mdi->parent->instanceID);
449
+ goto endlocks;
450
+ }
451
+
452
+ do {
453
+ ret = SQLFetch(mdi->parent->conn.dbLocksSTMT);
454
+ switch (ret) {
455
+ case SQL_SUCCESS:
456
+ case SQL_SUCCESS_WITH_INFO:
457
+ break;
458
+ case SQL_NO_DATA:
459
+ default:
460
+ goto endlocks;
461
+ }
462
+
463
+ char *space = strchr(resource_type, ' ');
464
+ if (space)
465
+ *space = '\0';
466
+
467
+ struct mssql_lock_instance *mli =
468
+ dictionary_set(mdi->parent->locks_instances, resource_type, NULL, sizeof(*mli));
469
+ if (!mli)
470
+ continue;
471
+ } while (true);
472
+
473
+endlocks:
474
+ netdata_MSSQL_release_results(mdi->parent->conn.dbLocksSTMT);
475
+}
476
+
477
+int dict_mssql_databases_run_queries(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
478
{
479
struct mssql_db_instance *mdi = value;
480
const char *dbname = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
481
297
- mdi->MSSQLDatabaseDataFileSize.current.Data = netdata_MSSQL_fill_data_file_size(&mdi->parent->conn, (char *)dbname);
482
+ if (!mdi->collecting_data) {
483
+ goto enddrunquery;
484
+ }
485
+
486
+ // We failed to collect this for the database, so we are not going to try again
487
+ if (mdi->MSSQLDatabaseDataFileSize.current.Data != ULONG_LONG_MAX)
488
+ mdi->MSSQLDatabaseDataFileSize.current.Data = netdata_MSSQL_fill_long_value(
489
+ mdi->parent->conn.dataFileSizeSTMT, NETDATA_QUERY_DATA_FILE_SIZE_MASK, dbname, mdi->parent->instanceID);
490
+ else {
491
+ mdi->collecting_data = false;
492
+ goto enddrunquery;
493
+ }
494
+
495
+ dict_mssql_fill_transactions(mdi, dbname);
496
+ dict_mssql_fill_locks(mdi, dbname);
497
+
498
+enddrunquery:
499
+ return 1;
500
+}
501
+
502
+#define NETDATA_QUERY_CHECK_PERM \
503
+ "SELECT CASE WHEN IS_SRVROLEMEMBER('sysadmin') = 1 OR HAS_PERMS_BY_NAME(null, null, 'VIEW SERVER STATE') = 1 THEN 1 ELSE 0 END AS has_permission;"
504
+long metdata_mssql_check_permission(struct mssql_instance *mi)
505
+{
506
+ static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
507
+ long perm = 0;
508
+ SQLLEN col_data_len = 0;
509
+
510
+ if (++next_try != NETDATA_MSSQL_NEXT_TRY)
511
+ return 1;
512
+
513
+ next_try = 0;
514
+
515
+ SQLRETURN ret;
516
+
517
+ ret = SQLExecDirect(mi->conn.checkPermSTMT, (SQLCHAR *)NETDATA_QUERY_CHECK_PERM, SQL_NTS);
518
+ if (ret != SQL_SUCCESS) {
519
+ netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
520
+ perm = LONG_MAX;
521
+ goto endperm;
522
+ }
523
+
524
+ ret = SQLBindCol(mi->conn.checkPermSTMT, 1, SQL_C_LONG, &perm, sizeof(perm), &col_data_len);
525
+
526
+ if (ret != SQL_SUCCESS) {
527
+ netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
528
+ perm = LONG_MAX;
529
+ goto endperm;
530
+ }
531
+
532
+ ret = SQLFetch(mi->conn.checkPermSTMT);
533
+ if (ret != SQL_SUCCESS) {
534
+ netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.checkPermSTMT, NETDATA_MSSQL_ODBC_FETCH, mi->instanceID);
535
+ perm = LONG_MAX;
536
+ goto endperm;
537
+ }
538
+
539
+endperm:
540
+ netdata_MSSQL_release_results(mi->conn.checkPermSTMT);
541
+ return perm;
542
+}
543
+
544
+void metdata_mssql_fill_dictionary_from_db(struct mssql_instance *mi)
545
+{
546
+ char dbname[SQLSERVER_MAX_NAME_LENGTH + 1];
547
+ SQLLEN col_data_len = 0;
548
+
549
+ static int next_try = NETDATA_MSSQL_NEXT_TRY - 1;
550
+
551
+ if (++next_try != NETDATA_MSSQL_NEXT_TRY)
552
+ return;
553
+
554
+ next_try = 0;
555
+
556
+ SQLRETURN ret;
557
+
558
+ ret = SQLExecDirect(mi->conn.databaseListSTMT, (SQLCHAR *)NETDATA_QUERY_LIST_DB, SQL_NTS);
559
+ if (ret != SQL_SUCCESS) {
560
+ netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.databaseListSTMT, NETDATA_MSSQL_ODBC_QUERY, mi->instanceID);
561
+ goto enddblist;
562
+ }
563
+
564
+ ret = SQLBindCol(mi->conn.databaseListSTMT, 1, SQL_C_CHAR, dbname, sizeof(dbname), &col_data_len);
565
+
566
+ if (ret != SQL_SUCCESS) {
567
+ netdata_MSSQL_error(SQL_HANDLE_STMT, mi->conn.databaseListSTMT, NETDATA_MSSQL_ODBC_PREPARE, mi->instanceID);
568
+ goto enddblist;
569
+ }
570
+
571
+ do {
572
+ ret = SQLFetch(mi->conn.databaseListSTMT);
573
+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
574
+ goto enddblist;
575
+ }
576
+
577
+ struct mssql_db_instance *mdi = dictionary_set(mi->databases, dbname, NULL, sizeof(*mdi));
578
+ if (!mdi)
579
+ continue;
580
+
581
+ mdi->updated = 0;
582
+ if (!mdi->parent) {
583
+ mdi->parent = mi;
584
+ }
585
+ } while (true);
586
+
587
+enddblist:
588
+ netdata_MSSQL_release_results(mi->conn.databaseListSTMT);
589
}
590
591
static bool netdata_MSSQL_initialize_conection(struct netdata_mssql_conn *nmc)
@@ -336,7 +627,7 @@ static bool netdata_MSSQL_initialize_conection(struct netdata_mssql_conn *nmc)
627
case SQL_INVALID_HANDLE:
628
case SQL_ERROR:
629
default:
339
- netdata_MSSQL_error(SQL_HANDLE_DBC, nmc->netdataSQLHDBc, NETDATA_MSSQL_ODBC_CONNECT);
630
+ netdata_MSSQL_error(SQL_HANDLE_DBC, nmc->netdataSQLHDBc, NETDATA_MSSQL_ODBC_CONNECT, NULL);
631
retConn = FALSE;
632
break;
633
case SQL_SUCCESS:
@@ -346,9 +637,25 @@ static bool netdata_MSSQL_initialize_conection(struct netdata_mssql_conn *nmc)
637
}
638
639
if (retConn) {
640
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->checkPermSTMT);
641
+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
642
+ retConn = FALSE;
643
+
644
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->databaseListSTMT);
645
+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
646
+ retConn = FALSE;
647
+
648
ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dataFileSizeSTMT);
649
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
650
retConn = FALSE;
651
+
652
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbTransactionSTMT);
653
+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
654
+ retConn = FALSE;
655
+
656
+ ret = SQLAllocHandle(SQL_HANDLE_STMT, nmc->netdataSQLHDBc, &nmc->dbLocksSTMT);
657
+ if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
658
+ retConn = FALSE;
659
}
660
661
return retConn;
@@ -444,15 +751,9 @@ void dict_mssql_insert_locks_cb(const DICTIONARY_ITEM *item __maybe_unused, void
751
752
void dict_mssql_insert_databases_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
753
{
447
- struct mssql_db_instance *ptr = value;
448
-
449
- // https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-databases-object
450
- ptr->MSSQLDatabaseActiveTransactions.key = "Active Transactions";
451
- ptr->MSSQLDatabaseBackupRestoreOperations.key = "Backup/Restore Throughput/sec";
452
- ptr->MSSQLDatabaseLogFlushed.key = "Log Bytes Flushed/sec";
453
- ptr->MSSQLDatabaseLogFlushes.key = "Log Flushes/sec";
454
- ptr->MSSQLDatabaseTransactions.key = "Transactions/sec";
455
- ptr->MSSQLDatabaseWriteTransactions.key = "Write Transactions/sec";
754
+ struct mssql_db_instance *mdi = value;
755
+
756
+ mdi->collecting_data = true;
757
}
758
759
// Options
@@ -505,7 +806,11 @@ static void netdata_read_config_options(struct netdata_mssql_conn *dbconn)
806
{
807
dbconn->netdataSQLEnv = NULL;
808
dbconn->netdataSQLHDBc = NULL;
809
+ dbconn->checkPermSTMT = NULL;
810
+ dbconn->databaseListSTMT = NULL;
811
dbconn->dataFileSizeSTMT = NULL;
812
+ dbconn->dbTransactionSTMT = NULL;
813
+ dbconn->dbLocksSTMT = NULL;
814
815
dbconn->is_connected = FALSE;
816
@@ -1068,15 +1373,15 @@ void dict_mssql_locks_wait_charts(struct mssql_instance *mi, int update_every)
1373
if (!mi->st_lockWait) {
1374
char id[RRD_ID_LENGTH_MAX + 1];
1375
1071
- snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_locks_lock_wait", mi->instanceID);
1376
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_lock_wait", mi->instanceID);
1377
netdata_fix_chart_name(id);
1378
mi->st_lockWait = rrdset_create_localhost(
1379
"mssql",
1380
id,
1381
NULL,
1382
"locks",
1078
- "mssql.instance_locks_lock_wait",
1079
- "Lock requests that required the caller to wait.",
1383
+ "mssql.instance_resource_lock_wait",
1384
+ "Lock requests that required the caller to wait per resource.",
1385
"locks/s",
1386
PLUGIN_WINDOWS_NAME,
1387
"PerflibMSSQL",
@@ -1088,36 +1393,24 @@ void dict_mssql_locks_wait_charts(struct mssql_instance *mi, int update_every)
1393
}
1394
}
1395
1091
-void dict_mssql_locks_wait_dimension(struct mssql_instance *mi, struct mssql_lock_instance *mli)
1092
-{
1093
- if (!mli->rd_lockWait) {
1094
- char id[RRD_ID_LENGTH_MAX + 1];
1095
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s", mli->resourceID);
1096
- netdata_fix_chart_name(id);
1097
-
1098
- mli->rd_lockWait = rrddim_add(mi->st_lockWait, id, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1099
- }
1100
- rrddim_set_by_pointer(mi->st_lockWait, mli->rd_lockWait, (collected_number)(mli->lockWait.current.Data));
1101
-}
1102
-
1396
void dict_mssql_dead_locks_charts(struct mssql_instance *mi, int update_every)
1397
{
1398
if (!mi->st_deadLocks) {
1399
char id[RRD_ID_LENGTH_MAX + 1];
1400
1108
- snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_locks_deadlocks", mi->instanceID);
1401
+ snprintfz(id, RRD_ID_LENGTH_MAX, "instance_%s_resource_deadlocks", mi->instanceID);
1402
netdata_fix_chart_name(id);
1403
mi->st_deadLocks = rrdset_create_localhost(
1404
"mssql",
1405
id,
1406
NULL,
1407
"locks",
1115
- "mssql.instance_locks_deadlocks",
1116
- "Lock requests that resulted in deadlock.",
1408
+ "mssql.instance_resource_deadlocks",
1409
+ "Active lock requests that resulted in deadlock per resource.",
1410
"deadlocks/s",
1411
PLUGIN_WINDOWS_NAME,
1412
"PerflibMSSQL",
1120
- PRIO_MSSQL_LOCKS_DEADLOCK,
1413
+ PRIO_MSSQL_LOCKS_DEADLOCK_PER_RESOURCE,
1414
update_every,
1415
RRDSET_TYPE_LINE);
1416
@@ -1125,18 +1418,6 @@ void dict_mssql_dead_locks_charts(struct mssql_instance *mi, int update_every)
1418
}
1419
}
1420
1128
-void dict_mssql_deadlocks_dimension(struct mssql_instance *mi, struct mssql_lock_instance *mli)
1129
-{
1130
- if (!mli->rd_deadLocks) {
1131
- char id[RRD_ID_LENGTH_MAX + 1];
1132
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s", mli->resourceID);
1133
- netdata_fix_chart_name(id);
1134
-
1135
- mli->rd_deadLocks = rrddim_add(mi->st_deadLocks, id, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1136
- }
1137
- rrddim_set_by_pointer(mi->st_deadLocks, mli->rd_deadLocks, (collected_number)mli->deadLocks.current.Data);
1138
-}
1139
-
1421
static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *mi, int update_every)
1422
{
1423
PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, mi->objectName[NETDATA_MSSQL_LOCKS]);
@@ -1148,29 +1429,6 @@ static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *m
1429
1430
dict_mssql_locks_wait_charts(mi, update_every);
1431
dict_mssql_dead_locks_charts(mi, update_every);
1151
- PERF_INSTANCE_DEFINITION *pi = NULL;
1152
- for (LONG i = 0; i < pObjectType->NumInstances; i++) {
1153
- pi = perflibForEachInstance(pDataBlock, pObjectType, pi);
1154
- if (!pi)
1155
- break;
1156
-
1157
- if (!getInstanceName(pDataBlock, pObjectType, pi, windows_shared_buffer, sizeof(windows_shared_buffer)))
1158
- strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
1159
-
1160
- if (!strcasecmp(windows_shared_buffer, "_Total"))
1161
- continue;
1162
-
1163
- struct mssql_lock_instance *mli =
1164
- dictionary_set(mi->locks_instances, windows_shared_buffer, NULL, sizeof(*mli));
1165
- if (!mli)
1166
- continue;
1167
-
1168
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mli->lockWait))
1169
- dict_mssql_locks_wait_dimension(mi, mli);
1170
-
1171
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mli->deadLocks))
1172
- dict_mssql_deadlocks_dimension(mi, mli);
1173
- }
1432
1433
if (mi->st_lockWait)
1434
rrdset_done(mi->st_lockWait);
@@ -1181,6 +1439,9 @@ static void do_mssql_locks(PERF_DATA_BLOCK *pDataBlock, struct mssql_instance *m
1439
1440
static void mssql_database_backup_restore_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1441
{
1442
+ if (unlikely(!mli->parent->conn.is_connected))
1443
+ return;
1444
+
1445
char id[RRD_ID_LENGTH_MAX + 1];
1446
1447
if (!mli->st_db_backup_restore_operations) {
@@ -1213,18 +1474,19 @@ static void mssql_database_backup_restore_chart(struct mssql_db_instance *mli, c
1474
rrddim_add(mli->st_db_backup_restore_operations, "backup", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1475
}
1476
1216
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_BACKUP_RESTORE_OP)) {
1217
- rrddim_set_by_pointer(
1218
- mli->st_db_backup_restore_operations,
1219
- mli->rd_db_backup_restore_operations,
1220
- (collected_number)mli->MSSQLDatabaseBackupRestoreOperations.current.Data);
1221
- }
1477
+ rrddim_set_by_pointer(
1478
+ mli->st_db_backup_restore_operations,
1479
+ mli->rd_db_backup_restore_operations,
1480
+ (collected_number)mli->MSSQLDatabaseBackupRestoreOperations.current.Data);
1481
1482
rrdset_done(mli->st_db_backup_restore_operations);
1483
}
1484
1485
static void mssql_database_log_flushes_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1486
{
1487
+ if (unlikely(!mli->parent->conn.is_connected))
1488
+ return;
1489
+
1490
char id[RRD_ID_LENGTH_MAX + 1];
1491
1492
if (!mli->st_db_log_flushes) {
@@ -1252,18 +1514,17 @@ static void mssql_database_log_flushes_chart(struct mssql_db_instance *mli, cons
1514
mli->rd_db_log_flushes = rrddim_add(mli->st_db_log_flushes, "flushes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1515
}
1516
1255
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHES)) {
1256
- rrddim_set_by_pointer(
1257
- mli->st_db_log_flushes,
1258
- mli->rd_db_log_flushes,
1259
- (collected_number)mli->MSSQLDatabaseLogFlushes.current.Data);
1260
- }
1517
+ rrddim_set_by_pointer(
1518
+ mli->st_db_log_flushes, mli->rd_db_log_flushes, (collected_number)mli->MSSQLDatabaseLogFlushes.current.Data);
1519
1520
rrdset_done(mli->st_db_log_flushes);
1521
}
1522
1523
static void mssql_database_log_flushed_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1524
{
1525
+ if (unlikely(!mli->parent->conn.is_connected))
1526
+ return;
1527
+
1528
char id[RRD_ID_LENGTH_MAX + 1];
1529
1530
if (!mli->st_db_log_flushed) {
@@ -1291,18 +1552,17 @@ static void mssql_database_log_flushed_chart(struct mssql_db_instance *mli, cons
1552
mli->rd_db_log_flushed = rrddim_add(mli->st_db_log_flushed, "flushed", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1553
}
1554
1294
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHED)) {
1295
- rrddim_set_by_pointer(
1296
- mli->st_db_log_flushed,
1297
- mli->rd_db_log_flushed,
1298
- (collected_number)mli->MSSQLDatabaseLogFlushed.current.Data);
1299
- }
1555
+ rrddim_set_by_pointer(
1556
+ mli->st_db_log_flushed, mli->rd_db_log_flushed, (collected_number)mli->MSSQLDatabaseLogFlushed.current.Data);
1557
1558
rrdset_done(mli->st_db_log_flushed);
1559
}
1560
1561
static void mssql_transactions_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1562
{
1563
+ if (unlikely(!mli->parent->conn.is_connected))
1564
+ return;
1565
+
1566
char id[RRD_ID_LENGTH_MAX + 1];
1567
1568
if (!mli->st_db_transactions) {
@@ -1331,18 +1591,19 @@ static void mssql_transactions_chart(struct mssql_db_instance *mli, const char *
1591
rrddim_add(mli->st_db_transactions, "transactions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1592
}
1593
1334
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_TRANSACTIONS)) {
1335
- rrddim_set_by_pointer(
1336
- mli->st_db_transactions,
1337
- mli->rd_db_transactions,
1338
- (collected_number)mli->MSSQLDatabaseTransactions.current.Data);
1339
- }
1594
+ rrddim_set_by_pointer(
1595
+ mli->st_db_transactions,
1596
+ mli->rd_db_transactions,
1597
+ (collected_number)mli->MSSQLDatabaseTransactions.current.Data);
1598
1599
rrdset_done(mli->st_db_transactions);
1600
}
1601
1602
static void mssql_write_transactions_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1603
{
1604
+ if (unlikely(!mli->parent->conn.is_connected))
1605
+ return;
1606
+
1607
char id[RRD_ID_LENGTH_MAX + 1];
1608
1609
if (!mli->st_db_write_transactions) {
@@ -1372,18 +1633,163 @@ static void mssql_write_transactions_chart(struct mssql_db_instance *mli, const
1633
rrddim_add(mli->st_db_write_transactions, "write", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1634
}
1635
1375
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_WRITE_TRANSACTIONS)) {
1376
- rrddim_set_by_pointer(
1377
- mli->st_db_write_transactions,
1378
- mli->rd_db_write_transactions,
1379
- (collected_number)mli->MSSQLDatabaseWriteTransactions.current.Data);
1380
- }
1636
+ rrddim_set_by_pointer(
1637
+ mli->st_db_write_transactions,
1638
+ mli->rd_db_write_transactions,
1639
+ (collected_number)mli->MSSQLDatabaseWriteTransactions.current.Data);
1640
1641
rrdset_done(mli->st_db_write_transactions);
1642
}
1643
1644
+static void mssql_lockwait_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1645
+{
1646
+ if (unlikely(!mli->parent->conn.is_connected))
1647
+ return;
1648
+
1649
+ char id[RRD_ID_LENGTH_MAX + 1];
1650
+
1651
+ if (!mli->st_db_lockwait) {
1652
+ snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lockwait", db, mli->parent->instanceID);
1653
+ netdata_fix_chart_name(id);
1654
+ mli->st_db_lockwait = rrdset_create_localhost(
1655
+ "mssql",
1656
+ id,
1657
+ NULL,
1658
+ "locks",
1659
+ "mssql.database_lockwait",
1660
+ "Lock requests that required the caller to wait.",
1661
+ "locks/s",
1662
+ PLUGIN_WINDOWS_NAME,
1663
+ "PerflibMSSQL",
1664
+ PRIO_MSSQL_DATABASE_LOCKWAIT_PER_SECOND,
1665
+ update_every,
1666
+ RRDSET_TYPE_LINE);
1667
+
1668
+ rrdlabels_add(mli->st_db_lockwait->rrdlabels, "mssql_instance", mli->parent->instanceID, RRDLABEL_SRC_AUTO);
1669
+ rrdlabels_add(mli->st_db_lockwait->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
1670
+
1671
+ mli->rd_db_lockwait = rrddim_add(mli->st_db_lockwait, "lock", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1672
+ }
1673
+
1674
+ rrddim_set_by_pointer(
1675
+ mli->st_db_lockwait, mli->rd_db_lockwait, (collected_number)mli->MSSQLDatabaseLockWaitSec.current.Data);
1676
+
1677
+ rrdset_done(mli->st_db_lockwait);
1678
+}
1679
+
1680
+static void mssql_deadlock_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1681
+{
1682
+ if (unlikely(!mli->parent->conn.is_connected))
1683
+ return;
1684
+
1685
+ char id[RRD_ID_LENGTH_MAX + 1];
1686
+
1687
+ if (!mli->st_db_deadlock) {
1688
+ snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_deadlocks", db, mli->parent->instanceID);
1689
+ netdata_fix_chart_name(id);
1690
+ mli->st_db_deadlock = rrdset_create_localhost(
1691
+ "mssql",
1692
+ id,
1693
+ NULL,
1694
+ "locks",
1695
+ "mssql.database_deadlocks",
1696
+ "Lock requests that resulted in deadlock.",
1697
+ "deadlocks/s",
1698
+ PLUGIN_WINDOWS_NAME,
1699
+ "PerflibMSSQL",
1700
+ PRIO_MSSQL_DATABASE_DEADLOCKS_PER_SECOND,
1701
+ update_every,
1702
+ RRDSET_TYPE_LINE);
1703
+
1704
+ rrdlabels_add(mli->st_db_deadlock->rrdlabels, "mssql_instance", mli->parent->instanceID, RRDLABEL_SRC_AUTO);
1705
+ rrdlabels_add(mli->st_db_deadlock->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
1706
+
1707
+ mli->rd_db_deadlock = rrddim_add(mli->st_db_deadlock, "deadlocks", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1708
+ }
1709
+
1710
+ rrddim_set_by_pointer(
1711
+ mli->st_db_deadlock, mli->rd_db_deadlock, (collected_number)mli->MSSQLDatabaseDeadLockSec.current.Data);
1712
+
1713
+ rrdset_done(mli->st_db_deadlock);
1714
+}
1715
+
1716
+static void mssql_lock_request_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1717
+{
1718
+ if (unlikely(!mli->parent->conn.is_connected))
1719
+ return;
1720
+
1721
+ char id[RRD_ID_LENGTH_MAX + 1];
1722
+
1723
+ if (!mli->st_lock_requests) {
1724
+ snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_requests", db, mli->parent->instanceID);
1725
+ netdata_fix_chart_name(id);
1726
+ mli->st_lock_requests = rrdset_create_localhost(
1727
+ "mssql",
1728
+ id,
1729
+ NULL,
1730
+ "locks",
1731
+ "mssql.database_lock_requests",
1732
+ "Number of new locks and lock conversions requested.",
1733
+ "requests/s",
1734
+ PLUGIN_WINDOWS_NAME,
1735
+ "PerflibMSSQL",
1736
+ PRIO_MSSQL_DATABASE_LOCK_REQUESTS_SEC,
1737
+ update_every,
1738
+ RRDSET_TYPE_LINE);
1739
+
1740
+ rrdlabels_add(mli->st_lock_requests->rrdlabels, "mssql_instance", mli->parent->instanceID, RRDLABEL_SRC_AUTO);
1741
+ rrdlabels_add(mli->st_lock_requests->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
1742
+
1743
+ mli->rd_lock_requests = rrddim_add(mli->st_lock_requests, "requests", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1744
+ }
1745
+
1746
+ rrddim_set_by_pointer(
1747
+ mli->st_lock_requests, mli->rd_lock_requests, (collected_number)mli->MSSQLDatabaseLockRequestsSec.current.Data);
1748
+
1749
+ rrdset_done(mli->st_lock_requests);
1750
+}
1751
+
1752
+static void mssql_lock_timeout_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1753
+{
1754
+ if (unlikely(!mli->parent->conn.is_connected))
1755
+ return;
1756
+
1757
+ char id[RRD_ID_LENGTH_MAX + 1];
1758
+
1759
+ if (!mli->st_lock_timeouts) {
1760
+ snprintfz(id, RRD_ID_LENGTH_MAX, "db_%s_instance_%s_lock_timeouts", db, mli->parent->instanceID);
1761
+ netdata_fix_chart_name(id);
1762
+ mli->st_lock_timeouts = rrdset_create_localhost(
1763
+ "mssql",
1764
+ id,
1765
+ NULL,
1766
+ "locks",
1767
+ "mssql.database_lock_timeouts",
1768
+ "Lock that timed out.",
1769
+ "timeouts/s",
1770
+ PLUGIN_WINDOWS_NAME,
1771
+ "PerflibMSSQL",
1772
+ PRIO_MSSQL_DATABASE_LOCKS_TIMEOUT_PER_SECOND,
1773
+ update_every,
1774
+ RRDSET_TYPE_LINE);
1775
+
1776
+ rrdlabels_add(mli->st_lock_timeouts->rrdlabels, "mssql_instance", mli->parent->instanceID, RRDLABEL_SRC_AUTO);
1777
+ rrdlabels_add(mli->st_lock_timeouts->rrdlabels, "database", db, RRDLABEL_SRC_AUTO);
1778
+
1779
+ mli->rd_lock_timeouts = rrddim_add(mli->st_lock_timeouts, "timeouts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1780
+ }
1781
+
1782
+ rrddim_set_by_pointer(
1783
+ mli->st_lock_timeouts, mli->rd_lock_timeouts, (collected_number)mli->MSSQLDatabaseLockTimeoutsSec.current.Data);
1784
+
1785
+ rrdset_done(mli->st_lock_timeouts);
1786
+}
1787
+
1788
static void mssql_active_transactions_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1789
{
1790
+ if (unlikely(!mli->parent->conn.is_connected))
1791
+ return;
1792
+
1793
char id[RRD_ID_LENGTH_MAX + 1];
1794
1795
if (!mli->st_db_active_transactions) {
@@ -1413,19 +1819,17 @@ static void mssql_active_transactions_chart(struct mssql_db_instance *mli, const
1819
rrddim_add(mli->st_db_active_transactions, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1820
}
1821
1416
- if (mli->updated & (1 << NETDATA_MSSQL_ENUM_MDI_IDX_ACTIVE_TRANSACTIONS)) {
1417
- rrddim_set_by_pointer(
1418
- mli->st_db_active_transactions,
1419
- mli->rd_db_active_transactions,
1420
- (collected_number)mli->MSSQLDatabaseActiveTransactions.current.Data);
1421
- }
1822
+ rrddim_set_by_pointer(
1823
+ mli->st_db_active_transactions,
1824
+ mli->rd_db_active_transactions,
1825
+ (collected_number)mli->MSSQLDatabaseActiveTransactions.current.Data);
1826
1827
rrdset_done(mli->st_db_active_transactions);
1828
}
1829
1830
static inline void mssql_data_file_size_chart(struct mssql_db_instance *mli, const char *db, int update_every)
1831
{
1428
- if (unlikely(!mli->parent->conn.is_connected) || mli->MSSQLDatabaseDataFileSize.current.Data == ULONG_LONG_MAX)
1832
+ if (unlikely(!mli->parent->conn.is_connected))
1833
return;
1834
1835
char id[RRD_ID_LENGTH_MAX + 1];
@@ -1467,6 +1871,10 @@ int dict_mssql_databases_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, v
1871
struct mssql_db_instance *mli = value;
1872
const char *db = dictionary_acquired_item_name((DICTIONARY_ITEM *)item);
1873
1874
+ if (!mli->collecting_data) {
1875
+ goto endchartcb;
1876
+ }
1877
+
1878
int *update_every = data;
1879
1880
void (*transaction_chart[])(struct mssql_db_instance *, const char *, int) = {
@@ -1477,6 +1885,10 @@ int dict_mssql_databases_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, v
1885
mssql_database_log_flushes_chart,
1886
mssql_active_transactions_chart,
1887
mssql_write_transactions_chart,
1888
+ mssql_lockwait_chart,
1889
+ mssql_deadlock_chart,
1890
+ mssql_lock_timeout_chart,
1891
+ mssql_lock_request_chart,
1892
1893
// Last function pointer must be NULL
1894
NULL};
@@ -1486,6 +1898,7 @@ int dict_mssql_databases_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, v
1898
transaction_chart[i](mli, db, *update_every);
1899
}
1900
1901
+endchartcb:
1902
return 1;
1903
}
1904
@@ -1511,28 +1924,9 @@ static void do_mssql_databases(PERF_DATA_BLOCK *pDataBlock, struct mssql_instanc
1924
if (!mdi)
1925
continue;
1926
1514
- mdi->updated = 0;
1927
if (!mdi->parent) {
1928
mdi->parent = mi;
1929
}
1518
-
1519
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseActiveTransactions))
1520
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_ACTIVE_TRANSACTIONS);
1521
-
1522
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseBackupRestoreOperations))
1523
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_BACKUP_RESTORE_OP);
1524
-
1525
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseLogFlushed))
1526
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHED);
1527
-
1528
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseLogFlushes))
1529
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_LOG_FLUSHES);
1530
-
1531
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseTransactions))
1532
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_TRANSACTIONS);
1533
-
1534
- if (perflibGetObjectCounter(pDataBlock, pObjectType, &mdi->MSSQLDatabaseWriteTransactions))
1535
- mdi->updated |= (1 << NETDATA_MSSQL_ENUM_MDI_IDX_WRITE_TRANSACTIONS);
1930
}
1931
1932
dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_charts_cb, &update_every);
@@ -1670,13 +2064,36 @@ static void do_mssql_memory_mgr(PERF_DATA_BLOCK *pDataBlock, struct mssql_instan
2064
}
2065
}
2066
2067
+int netdata_mssql_reset_value(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2068
+{
2069
+ struct mssql_db_instance *mdi = value;
2070
+
2071
+ mdi->collecting_data = false;
2072
+
2073
+ return 1;
2074
+}
2075
+
2076
int dict_mssql_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused)
2077
{
2078
struct mssql_instance *mi = value;
2079
+ static long have_perm = 1;
2080
int *update_every = data;
2081
1678
- if (mi->conn.is_connected) {
1679
- dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_run_query, NULL);
2082
+ if (mi->conn.is_connected && have_perm) {
2083
+ have_perm = metdata_mssql_check_permission(mi);
2084
+ if (!have_perm) {
2085
+ nd_log(
2086
+ NDLS_COLLECTORS,
2087
+ NDLP_ERR,
2088
+ "User %s does not have permission to run queries on %s",
2089
+ mi->conn.username,
2090
+ mi->instanceID);
2091
+ } else {
2092
+ metdata_mssql_fill_dictionary_from_db(mi);
2093
+ dictionary_sorted_walkthrough_read(mi->databases, dict_mssql_databases_run_queries, NULL);
2094
+ }
2095
+ } else {
2096
+ dictionary_sorted_walkthrough_read(mi->databases, netdata_mssql_reset_value, NULL);
2097
}
2098
2099
static void (*doMSSQL[])(PERF_DATA_BLOCK *, struct mssql_instance *, int) = {
src/collectors/windows.plugin/windows_plugin.h
+6
-1
@@ -69,6 +69,11 @@ enum PERFLIB_PRIO {
69
PRIO_MSSQL_DATABASE_LOG_FLUSHES,
70
PRIO_MSSQL_DATABASE_LOG_FLUSHED,
71
72
+ PRIO_MSSQL_DATABASE_LOCKWAIT_PER_SECOND,
73
+ PRIO_MSSQL_DATABASE_DEADLOCKS_PER_SECOND,
74
+ PRIO_MSSQL_DATABASE_LOCKS_TIMEOUT_PER_SECOND,
75
+ PRIO_MSSQL_DATABASE_LOCK_REQUESTS_SEC,
76
+
77
PRIO_MSSQL_DATABASE_DATA_FILE_SIZE,
78
79
PRIO_MSSQL_STATS_BATCH_REQUEST,
@@ -91,7 +96,7 @@ enum PERFLIB_PRIO {
96
PRIO_MSSQL_MEMMGR_PENDING_MEMORY_GRANTS,
97
98
PRIO_MSSQL_LOCKS_WAIT,
94
- PRIO_MSSQL_LOCKS_DEADLOCK,
99
+ PRIO_MSSQL_LOCKS_DEADLOCK_PER_RESOURCE,
100
101
PRIO_MSSQL_SQL_ERRORS,
102