Compare commits

...

10 Commits

Author SHA1 Message Date
Jesse Qu fd2463e981 added to our repos 2025-05-09 18:28:37 +08:00
elv-gilles c31d402b72
fix(parsers.json_v2): Handle measurements with multiple objects correctly (#16878) 2025-05-08 12:07:01 +01:00
dependabot[bot] f5404aee67
chore(deps): Bump github.com/aws/aws-sdk-go-v2/service/kinesis from 1.33.3 to 1.35.0 (#16968)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-08 12:00:02 +01:00
skartikey 187a1931e5
chore(inputs.sqlserver): Migrate Azure AD Authentication from ADAL to MSAL (#16730)
Co-authored-by: Sven Rebhan <36194019+srebhan@users.noreply.github.com>
2025-05-08 11:58:07 +01:00
Joseph Zhang 9465e7182a
docs: fill the missed symbol \ in WINDOWS_SERVICE.md (#16976) 2025-05-07 12:37:01 +01:00
dependabot[bot] fd1964bfd7
chore(deps): Bump github.com/aws/aws-msk-iam-sasl-signer-go from 1.0.1 to 1.0.3 (#16954)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 12:35:36 +01:00
dependabot[bot] 5a29809eea
chore(deps): Bump github.com/rclone/rclone from 1.69.1 to 1.69.2 (#16964)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 12:34:35 +01:00
dependabot[bot] ed56d640f2
chore(deps): Bump golang.org/x/net from 0.39.0 to 0.40.0 (#16966)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 12:34:12 +01:00
dependabot[bot] d252bc83d3
chore(deps): Bump github.com/nats-io/nats.go from 1.41.2 to 1.42.0 (#16967)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 12:33:43 +01:00
dependabot[bot] 7cd6c00647
chore(deps): Bump github.com/hashicorp/consul/api from 1.32.0 to 1.32.1 (#16972)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-07 12:33:15 +01:00
12 changed files with 302 additions and 73 deletions

View File

@ -1,3 +1,4 @@
# ![tiger](assets/TelegrafTigerSmall.png "tiger") Telegraf
[![GoDoc](https://img.shields.io/badge/doc-reference-00ADD8.svg?logo=go)](https://godoc.org/github.com/influxdata/telegraf)

View File

@ -15,7 +15,7 @@ the general steps to set it up.
quotes:
```shell
> "C:Program Files\Telegraf\telegraf.exe" service install
> "C:\Program Files\Telegraf\telegraf.exe" service install
```
5. Edit the configuration file to meet your needs

12
go.mod
View File

@ -48,7 +48,7 @@ require (
github.com/aristanetworks/goarista v0.0.0-20190325233358-a123909ec740
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/awnumar/memguard v0.22.5
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.3
github.com/aws/aws-sdk-go-v2 v1.36.3
github.com/aws/aws-sdk-go-v2/config v1.29.14
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
@ -57,7 +57,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.48.0
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.43.1
github.com/aws/aws-sdk-go-v2/service/ec2 v1.215.0
github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.3
github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0
github.com/aws/aws-sdk-go-v2/service/sts v1.33.19
github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.30.2
github.com/aws/smithy-go v1.22.3
@ -114,7 +114,7 @@ require (
github.com/gosnmp/gosnmp v1.40.0
github.com/grid-x/modbus v0.0.0-20240503115206-582f2ab60a18
github.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358
github.com/hashicorp/consul/api v1.32.0
github.com/hashicorp/consul/api v1.32.1
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/influxdata/influxdb-observability/common v0.5.12
@ -151,7 +151,7 @@ require (
github.com/moby/ipvs v1.1.0
github.com/multiplay/go-ts3 v1.2.0
github.com/nats-io/nats-server/v2 v2.11.3
github.com/nats-io/nats.go v1.41.2
github.com/nats-io/nats.go v1.42.0
github.com/netsampler/goflow2/v2 v2.2.2
github.com/newrelic/newrelic-telemetry-sdk-go v0.8.1
github.com/nsqio/go-nsq v1.1.0
@ -176,7 +176,7 @@ require (
github.com/prometheus/procfs v0.16.1
github.com/prometheus/prometheus v0.54.1
github.com/rabbitmq/amqp091-go v1.10.0
github.com/rclone/rclone v1.69.1
github.com/rclone/rclone v1.69.2
github.com/redis/go-redis/v9 v9.8.0
github.com/riemann/riemann-go-client v0.5.1-0.20211206220514-f58f10cdce16
github.com/robbiet480/go.nut v0.0.0-20220219091450-bd8f121e1fa1
@ -223,7 +223,7 @@ require (
go.step.sm/crypto v0.63.0
golang.org/x/crypto v0.38.0
golang.org/x/mod v0.24.0
golang.org/x/net v0.39.0
golang.org/x/net v0.40.0
golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.14.0
golang.org/x/sys v0.33.0

24
go.sum
View File

@ -878,8 +878,8 @@ github.com/awnumar/memcall v0.3.0 h1:8b/3Sptrtgejj2kLgL6M5F2r4OzTf19CTllO+gIXUg8
github.com/awnumar/memcall v0.3.0/go.mod h1:8xOx1YbfyuCg3Fy6TO8DK0kZUua3V42/goA5Ru47E8w=
github.com/awnumar/memguard v0.22.5 h1:PH7sbUVERS5DdXh3+mLo8FDcl1eIeVjJVYMnyuYpvuI=
github.com/awnumar/memguard v0.22.5/go.mod h1:+APmZGThMBWjnMlKiSM1X7MVpbIVewen2MTkqWkA/zE=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.3 h1:9vETuCJAV00CpMT8ONil8xvFuZrEgjTHWavXBd/DiPQ=
github.com/aws/aws-msk-iam-sasl-signer-go v1.0.3/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI=
github.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.18.0/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
@ -928,8 +928,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 h1:BbGDtTi0T1DYlmjBiCr/le3wzhA37O8QTC5/Ab8+EXk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6/go.mod h1:hLMJt7Q8ePgViKupeymbqI0la+t9/iYFBjxQCFwuAwI=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.3 h1:brQCC27V/e3wGeJ0JFh5InpH28saxe73Xpf0GXojn8M=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.3/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0 h1:Y8ONhfuFKHfx+gvgKbrsN8lOgNCHcnyHRLldRmhaI/M=
github.com/aws/aws-sdk-go-v2/service/kinesis v1.35.0/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPxhtt4DcBIHyCnmw=
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY=
github.com/aws/aws-sdk-go-v2/service/sso v1.12.10/go.mod h1:ouy2P4z6sJN70fR3ka3wD3Ro3KezSxU6eKGQI2+2fjI=
@ -1519,8 +1519,8 @@ github.com/gwos/tcg/sdk v0.0.0-20240830123415-f8a34bba6358/go.mod h1:h40FJV0HuUL
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.32.0 h1:5wp5u780Gri7c4OedGEPzmlUEzi0g2KyiPphSr6zjVg=
github.com/hashicorp/consul/api v1.32.0/go.mod h1:Z8YgY0eVPukT/17ejW+l+C7zJmKwgPHtjU1q16v/Y40=
github.com/hashicorp/consul/api v1.32.1 h1:0+osr/3t/aZNAdJX558crU3PEjVrG4x6715aZHRgceE=
github.com/hashicorp/consul/api v1.32.1/go.mod h1:mXUWLnxftwTmDv4W3lzxYCPD199iNLLUyLfLGFJbtl4=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.16.1 h1:V8TxTnImoPD5cj0U9Spl0TUxcytjcbbJeADFF07KdHg=
github.com/hashicorp/consul/sdk v0.16.1/go.mod h1:fSXvwxB2hmh1FMZCNl6PwX0Q/1wdWtHJcZ7Ea5tns0s=
@ -1964,8 +1964,8 @@ github.com/nats-io/jwt/v2 v2.7.4 h1:jXFuDDxs/GQjGDZGhNgH4tXzSUK6WQi2rsj4xmsNOtI=
github.com/nats-io/jwt/v2 v2.7.4/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
github.com/nats-io/nats-server/v2 v2.11.3 h1:AbGtXxuwjo0gBroLGGr/dE0vf24kTKdRnBq/3z/Fdoc=
github.com/nats-io/nats-server/v2 v2.11.3/go.mod h1:6Z6Fd+JgckqzKig7DYwhgrE7bJ6fypPHnGPND+DqgMY=
github.com/nats-io/nats.go v1.41.2 h1:5UkfLAtu/036s99AhFRlyNDI1Ieylb36qbGjJzHixos=
github.com/nats-io/nats.go v1.41.2/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nats.go v1.42.0 h1:ynIMupIOvf/ZWH/b2qda6WGKGNSjwOUutTpWRvAmhaM=
github.com/nats-io/nats.go v1.42.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@ -2150,8 +2150,8 @@ github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 h1:Y258uzX
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8/go.mod h1:bSJjRokAHHOhA+XFxplld8w2R/dXLH7Z3BZ532vhFwU=
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
github.com/rclone/rclone v1.69.1 h1:pjkfJlZjUk2DGj7vofG9baD+LKADm7zvoHFGQM1tPIA=
github.com/rclone/rclone v1.69.1/go.mod h1:VtzXeF46F7f6CtdCrxbZJdtsVVPBVYLGYyNG+KoTxIc=
github.com/rclone/rclone v1.69.2 h1:6uhFI7tiOrR5fy7Q88s49EqXc222mmwvZd7G9ne4lOE=
github.com/rclone/rclone v1.69.2/go.mod h1:fJPDOXUUPwN3KsbC3CGoVUuA5XU16IQvvMtrRqXYpvs=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
@ -2720,8 +2720,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

View File

@ -167,6 +167,11 @@ to use them.
## A list of queries to explicitly ignore.
exclude_query = ["SQLServerAvailabilityReplicaStates", "SQLServerDatabaseReplicaStates"]
## Force using the deprecated ADAL authentication method instead of the recommended
## MSAL method. Setting this option is not recommended and only exists for backward
## compatibility.
# use_deprecated_adal_authentication = false
## Queries enabled by default for database_type = "SQLServer" are -
## SQLServerPerformanceCounters, SQLServerWaitStatsCategorized, SQLServerDatabaseIO, SQLServerProperties, SQLServerMemoryClerks,
## SQLServerSchedulers, SQLServerRequests, SQLServerVolumeSpace, SQLServerCpu, SQLServerAvailabilityReplicaStates, SQLServerDatabaseReplicaStates,

View File

@ -0,0 +1,17 @@
package sqlserver
import "time"
// New token structure for Azure Identity SDK
type azureToken struct {
token string
expiresOn time.Time
}
// IsExpired helper method for Azure token expiry
func (t *azureToken) IsExpired() bool {
if t == nil {
return true
}
return time.Now().After(t.expiresOn)
}

View File

@ -35,6 +35,11 @@
## A list of queries to explicitly ignore.
exclude_query = ["SQLServerAvailabilityReplicaStates", "SQLServerDatabaseReplicaStates"]
## Force using the deprecated ADAL authentication method instead of the recommended
## MSAL method. Setting this option is not recommended and only exists for backward
## compatibility.
# use_deprecated_adal_authentication = false
## Queries enabled by default for database_type = "SQLServer" are -
## SQLServerPerformanceCounters, SQLServerWaitStatsCategorized, SQLServerDatabaseIO, SQLServerProperties, SQLServerMemoryClerks,
## SQLServerSchedulers, SQLServerRequests, SQLServerVolumeSpace, SQLServerCpu, SQLServerAvailabilityReplicaStates, SQLServerDatabaseReplicaStates,

View File

@ -11,6 +11,9 @@ import (
"sync"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
// Legacy ADAL package - kept for backward compatibility
"github.com/Azure/go-autorest/autorest/adal"
mssql "github.com/microsoft/go-mssqldb"
@ -55,9 +58,18 @@ type SQLServer struct {
HealthMetric bool `toml:"health_metric"`
Log telegraf.Logger `toml:"-"`
pools []*sql.DB
queries mapQuery
adalToken *adal.Token
pools []*sql.DB
queries mapQuery
// Legacy token - kept for backward compatibility
adalToken *adal.Token
// New token using Azure Identity SDK
azToken *azureToken
// Config option to use legacy ADAL authentication instead of the newer Azure Identity SDK
// When true, the deprecated ADAL library will be used
// When false (default), the new Azure Identity SDK will be used
UseAdalToken bool `toml:"use_deprecated_adal_authentication" deprecated:"1.40.0;migrate to MSAL authentication"`
muCacheLock sync.RWMutex
}
@ -70,7 +82,7 @@ type query struct {
type mapQuery map[string]query
// healthMetric struct tracking the number of attempted vs successful connections for each connection string
// healthMetric struct tracking the number of attempted vs. successful connections for each connection string
type healthMetric struct {
attemptedQueries int
successfulQueries int
@ -466,54 +478,124 @@ func (s *SQLServer) getDatabaseTypeToLog() string {
return logname
}
// Get Token Provider by loading cached token or refreshed token
// ------------------------------------------------------------------------------
// Token Provider Implementation
// ------------------------------------------------------------------------------
// getTokenProvider returns a function that provides authentication tokens for SQL Server.
//
// DEPRECATION NOTICE:
// The ADAL authentication library is deprecated and will be removed in a future version.
// It is strongly recommended to migrate to the Azure Identity SDK.
// See the migration documentation at: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-migration
//
// This implementation supports both authentication methods:
// 1. Azure Identity SDK (default, recommended)
// 2. Legacy ADAL library (deprecated, maintained for backward compatibility)
//
// To control which authentication library is used, set the use_deprecated_adal_authentication config option:
// - use_deprecated_adal_authentication = true : Use legacy ADAL authentication (deprecated)
// - use_deprecated_adal_authentication = false : Use Azure Identity SDK (recommended)
// - Not set : Use Azure Identity SDK (recommended)
func (s *SQLServer) getTokenProvider() (func() (string, error), error) {
var tokenString string
// load token
s.muCacheLock.RLock()
token, err := s.loadToken()
s.muCacheLock.RUnlock()
// if there's error while loading token or found an expired token, refresh token and save it
if err != nil || token.IsExpired() {
// refresh token within a write-lock
s.muCacheLock.Lock()
defer s.muCacheLock.Unlock()
// load token again, in case it's been refreshed by another thread
token, err = s.loadToken()
// check loaded token's error/validity, then refresh/save token
if err != nil || token.IsExpired() {
// get new token
spt, err := s.refreshToken()
if err != nil {
return nil, err
}
// use the refreshed token
tokenString = spt.OAuthToken()
} else {
// use locally cached token
tokenString = token.OAuthToken()
}
// Check if use_deprecated_adal_authentication config option is set to determine which auth method to use
// Default to using Azure Identity SDK if the config is not set
useAzureIdentity := !s.UseAdalToken
if useAzureIdentity {
s.Log.Debugf("Using Azure Identity SDK for authentication (recommended)")
} else {
// use locally cached token
tokenString = token.OAuthToken()
s.Log.Debugf("Using legacy ADAL for authentication (deprecated, will be removed in 1.40.0)")
}
// return acquired token
var tokenString string
if useAzureIdentity {
// Use Azure Identity SDK
s.muCacheLock.RLock()
token, err := s.loadAzureToken()
s.muCacheLock.RUnlock()
// If the token is nil, expired, or there was an error loading it, refresh the token
if err != nil || token == nil || token.IsExpired() {
// Refresh token within a write-lock
s.muCacheLock.Lock()
defer s.muCacheLock.Unlock()
// Load token again, in case it's been refreshed by another thread
token, err = s.loadAzureToken()
// Check loaded token's error/validity, then refresh/save token
if err != nil || token == nil || token.IsExpired() {
// Get new token
newToken, err := s.refreshAzureToken()
if err != nil {
return nil, err
}
// Use the refreshed token
tokenString = newToken.token
} else {
// Use locally cached token
tokenString = token.token
}
} else {
// Use locally cached token
tokenString = token.token
}
} else {
// Use legacy ADAL approach for backward compatibility
s.muCacheLock.RLock()
token, err := s.loadToken()
s.muCacheLock.RUnlock()
// If there's an error while loading token or found an expired token, refresh token and save it
if err != nil || token.IsExpired() {
// Refresh token within a write-lock
s.muCacheLock.Lock()
defer s.muCacheLock.Unlock()
// Load token again, in case it's been refreshed by another thread
token, err = s.loadToken()
// Check loaded token's error/validity, then refresh/save token
if err != nil || token.IsExpired() {
// Get new token
spt, err := s.refreshToken()
if err != nil {
return nil, err
}
// Use the refreshed token
tokenString = spt.OAuthToken()
} else {
// Use locally cached token
tokenString = token.OAuthToken()
}
} else {
// Use locally cached token
tokenString = token.OAuthToken()
}
}
// Return acquired token
//nolint:unparam // token provider function always returns nil error in this scenario
return func() (string, error) {
return tokenString, nil
}, nil
}
// Load token from in-mem cache
// ------------------------------------------------------------------------------
// Legacy ADAL Token Methods - Kept for backward compatibility
// ------------------------------------------------------------------------------
// loadToken loads a token from in-memory cache using the legacy ADAL method.
//
// Deprecated: This method uses the deprecated ADAL library and will be removed in a future version.
// Use the Azure Identity SDK instead of setting use_deprecated_adal_authentication = false or omitting it.
// See migration documentation: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-migration
func (s *SQLServer) loadToken() (*adal.Token, error) {
// This method currently does a simplistic task of reading a from variable (in-mem cache),
// however it's been structured here to allow extending the cache mechanism to a different approach in future
// This method currently does a simplistic task of reading from a variable (in-mem cache);
// however, it's been structured here to allow extending the cache mechanism to a different approach in future
if s.adalToken == nil {
return nil, errors.New("token is nil or failed to load existing token")
@ -522,31 +604,39 @@ func (s *SQLServer) loadToken() (*adal.Token, error) {
return s.adalToken, nil
}
// Refresh token for the resource, and save to in-mem cache
// refreshToken refreshes the token using the legacy ADAL method.
//
// Deprecated: This method uses the deprecated ADAL library and will be removed in a future version.
// Use the Azure Identity SDK instead of setting use_deprecated_adal_authentication = false or omitting it.
// See migration documentation: https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-migration
func (s *SQLServer) refreshToken() (*adal.Token, error) {
// get MSI endpoint to get a token
msiEndpoint, err := adal.GetMSIVMEndpoint()
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to get MSI endpoint: %w", err)
}
// get new token for the resource id
// get a new token for the resource id
var spt *adal.ServicePrincipalToken
if s.ClientID == "" {
// Using system-assigned managed identity
s.Log.Debugf("Using system-assigned managed identity with ADAL")
spt, err = adal.NewServicePrincipalTokenFromMSI(msiEndpoint, sqlAzureResourceID)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create service principal token from MSI: %w", err)
}
} else {
// Using user-assigned managed identity
s.Log.Debugf("Using user-assigned managed identity with ClientID: %s with ADAL", s.ClientID)
spt, err = adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, sqlAzureResourceID, s.ClientID)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create service principal token from MSI with user-assigned ID: %w", err)
}
}
// ensure token is fresh
// ensure the token is fresh
if err := spt.EnsureFresh(); err != nil {
return nil, err
return nil, fmt.Errorf("failed to ensure token freshness: %w", err)
}
// save token to local in-mem cache
@ -563,6 +653,64 @@ func (s *SQLServer) refreshToken() (*adal.Token, error) {
return s.adalToken, nil
}
// ------------------------------------------------------------------------------
// New Azure Identity SDK Token Methods
// ------------------------------------------------------------------------------
// loadAzureToken loads a token from in-memory cache using the Azure Identity SDK.
//
// This is the recommended authentication method for Azure SQL resources.
func (s *SQLServer) loadAzureToken() (*azureToken, error) {
// This method reads from variable (in-mem cache) but can be extended
// for different cache mechanisms in the future
if s.azToken == nil {
return nil, errors.New("token is nil or failed to load existing token")
}
return s.azToken, nil
}
// refreshAzureToken refreshes the token using the Azure Identity SDK.
//
// This is the recommended authentication method for Azure SQL resources.
func (s *SQLServer) refreshAzureToken() (*azureToken, error) {
var options *azidentity.ManagedIdentityCredentialOptions
if s.ClientID != "" {
options = &azidentity.ManagedIdentityCredentialOptions{
ID: azidentity.ResourceID(s.ClientID),
}
}
cred, err := azidentity.NewManagedIdentityCredential(options)
if err != nil {
return nil, fmt.Errorf("failed to create managed identity credential: %w", err)
}
// Get token from Azure AD
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
accessToken, err := cred.GetToken(ctx, policy.TokenRequestOptions{
Scopes: []string{sqlAzureResourceID + "/.default"},
})
if err != nil {
credType := "system-assigned"
if s.ClientID != "" {
credType = fmt.Sprintf("user-assigned (ClientID: %s)", s.ClientID)
}
return nil, fmt.Errorf("failed to get token using %s managed identity: %w", credType, err)
}
// Save token to cache
s.azToken = &azureToken{
token: accessToken.Token,
expiresOn: accessToken.ExpiresOn,
}
return s.azToken, nil
}
func init() {
inputs.Add("sqlserver", func() telegraf.Input {
return &SQLServer{

View File

@ -151,6 +151,8 @@ func (p *Parser) parseCriticalPath(input []byte) ([]telegraf.Metric, error) {
}
var metrics []telegraf.Metric
// timestamp defaults to current time
now := time.Now()
for _, c := range p.Configs {
// Measurement name can either be hardcoded, or parsed from the JSON using a GJSON path expression
@ -162,8 +164,8 @@ func (p *Parser) parseCriticalPath(input []byte) ([]telegraf.Metric, error) {
}
}
// timestamp defaults to current time, or can be parsed from the JSON using a GJSON path expression
timestamp := time.Now()
// timestamp can be parsed from the JSON using a GJSON path expression
timestamp := now
if c.TimestampPath != "" {
result := gjson.GetBytes(input, c.TimestampPath)
@ -200,13 +202,15 @@ func (p *Parser) parseCriticalPath(input []byte) ([]telegraf.Metric, error) {
return nil, err
}
metrics = append(metrics, cartesianProduct(tags, fields)...)
cmetrics := cartesianProduct(tags, fields)
if len(objects) != 0 && len(metrics) != 0 {
metrics = cartesianProduct(objects, metrics)
if len(objects) != 0 && len(cmetrics) != 0 {
cmetrics = cartesianProduct(objects, cmetrics)
} else {
metrics = append(metrics, objects...)
cmetrics = append(cmetrics, objects...)
}
metrics = append(metrics, cmetrics...)
}
for k, v := range p.DefaultTags {

View File

@ -0,0 +1,5 @@
api_http_status_codes 200=11586,201=16,202=14,204=8,404=43,500=0,503=0 1741532840501119000
api_requests requests=11668 1741532840501225000
api_responses responses=11667 1741532840501263000
api_av sessions_added=0,sessions_removed=0 1741544068286646000

View File

@ -0,0 +1,21 @@
{
"api": {
"http_status_codes": {
"200": 11586,
"201": 16,
"202": 14,
"204": 8,
"404": 43,
"500": 0,
"503": 0
},
"requests": 11668,
"responses": 11667,
"av": {
"sessions": {
"added": 0,
"removed": 0
}
}
}
}

View File

@ -0,0 +1,23 @@
[[inputs.file]]
files = ["./testdata/object_multiple/input.json"]
data_format = "json_v2"
[[inputs.file.json_v2]]
measurement_name = "api_http_status_codes"
[[inputs.file.json_v2.object]]
path = "api.http_status_codes"
[[inputs.file.json_v2]]
measurement_name = "api_requests"
[[inputs.file.json_v2.field]]
path = "api.requests"
[[inputs.file.json_v2]]
measurement_name = "api_responses"
[[inputs.file.json_v2.field]]
path = "api.responses"
[[inputs.file.json_v2]]
measurement_name = "api_av"
[[inputs.file.json_v2.object]]
path = "api.av"