From c3000cafb6aa304bdb1520dda55d1b0ffb793bd4 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:36:29 +0000 Subject: [PATCH 01/12] feat(dbi): add SQL Server receiver translator with 50 metrics - Enable 26 additional metrics for RDS parity (43 counter + 7 DB Load) - Configure query plan caching (1000 plans, 1hr TTL, 900KB max) - Enable query sample and top query collection - Add sample configuration files for Linux - Platform coverage: Linux 94%, Windows 100% Metrics include: - Performance & Resource (4): blocked processes, deadlocks, memory - Page & Buffer Pool (3): lookups, free list stalls - Wait Statistics (3): latch waits, lock timeouts - Transaction & Log (4): active transactions, log metrics - Database I/O (4): io, latency, operations, Resource Governor queue - Connection & Workload (3): login/logout rates, session count - Index & Query (3): index searches, full scans, errors - TempDB (2): space usage, version store New metrics: - sqlserver.database.io.stall_queued (Resource Governor I/O queue wait) - sqlserver.session.count (sessions by state) --- .../dbi_sqlserver_config_linux.conf | 15 + .../dbi_sqlserver_config_linux.json | 22 + .../dbi_sqlserver_config_linux.yaml | 1323 +++++++++++++++++ .../testdata/.sqlserver_credentials | 1 + .../otel/receiver/sqlserver/translator.go | 135 ++ .../receiver/sqlserver/translator_test.go | 153 ++ 6 files changed, 1649 insertions(+) create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.conf create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.json create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/testdata/.sqlserver_credentials create mode 100644 translator/translate/otel/receiver/sqlserver/translator.go create mode 100644 translator/translate/otel/receiver/sqlserver/translator_test.go diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.conf b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.conf new file mode 100644 index 00000000000..9d2168ce61a --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.conf @@ -0,0 +1,15 @@ +[agent] + collection_jitter = "0s" + debug = false + flush_interval = "1s" + flush_jitter = "0s" + hostname = "" + interval = "60s" + logfile = "/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log" + logtarget = "lumberjack" + metric_batch_size = 1000 + metric_buffer_limit = 10000 + omit_hostname = false + precision = "" + quiet = false + round_interval = false diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.json b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.json new file mode 100644 index 00000000000..1f343b8234c --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.json @@ -0,0 +1,22 @@ +{ + "agent": { + "region": "us-west-2" + }, + "opentelemetry": { + "collect": { + "database_insights": { + "sqlserver": [ + { + "endpoint": "localhost:1433", + "instance_name": "pentest-sqlserver", + "username": "cw_monitor", + "password_file": "sampleConfig/opentelemetry/testdata/.sqlserver_credentials", + "logs": { + "file_path": "/var/opt/mssql/log/errorlog" + } + } + ] + } + } + } +} diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml new file mode 100644 index 00000000000..220cc8d231b --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml @@ -0,0 +1,1323 @@ +connectors: + count/dbi_dbload_sqlserver: + datapoints: + metric.datapoint.count: + description: The number of data points observed. + logs: + sqlserver.active_sessions.by_db: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by database + sqlserver.active_sessions.by_host: + attributes: + - key: db.system.name + - key: network.peer.address + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by host + sqlserver.active_sessions.by_sql: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query hash + sqlserver.active_sessions.by_sql_wait: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query and wait category + sqlserver.active_sessions.by_user: + attributes: + - key: db.system.name + - key: user.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by user + sqlserver.active_sessions.by_wait: + attributes: + - key: db.system.name + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by wait category + sqlserver.active_sessions.count: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Total active sessions + metrics: + metric.count: + description: The number of metrics observed. + spanevents: + trace.span.event.count: + description: The number of span events observed. + spans: + trace.span.count: + description: The number of spans observed. + forward/opentelemetry: {} + signaltometrics/dbi_topsql_sqlserver: + logs: + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.execution_count"] != nil + description: Number of executions + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.execution_count + sum: + value: Int(attributes["sqlserver.execution_count"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_elapsed_time"] != nil + description: Total elapsed time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_elapsed_time + sum: + value: Double(attributes["sqlserver.total_elapsed_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_worker_time"] != nil + description: Total CPU (worker) time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_worker_time + sum: + value: Double(attributes["sqlserver.total_worker_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_reads"] != nil + description: Total logical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_reads + sum: + value: Int(attributes["sqlserver.total_logical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_writes"] != nil + description: Total logical writes (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_writes + sum: + value: Int(attributes["sqlserver.total_logical_writes"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_physical_reads"] != nil + description: Total physical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_physical_reads + sum: + value: Int(attributes["sqlserver.total_physical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_rows"] != nil + description: Total rows returned + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_rows + sum: + value: Int(attributes["sqlserver.total_rows"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_grant_kb"] != nil + description: Total memory grant (KB) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_grant_kb + sum: + value: Int(attributes["sqlserver.total_grant_kb"]) + unit: "" +exporters: + otlphttp/logs: + auth: + authenticator: agenthealth/opentelemetry_logs + compression: gzip + encoding: proto + idle_conn_timeout: 1m30s + logs_endpoint: https://logs.us-west-2.amazonaws.com/v1/logs + max_idle_conns: 100 + metrics_endpoint: "" + retry_on_failure: + enabled: true + initial_interval: 5s + max_elapsed_time: 5m0s + max_interval: 30s + multiplier: 1.5 + randomization_factor: 0.5 + sending_queue: + block_on_overflow: false + blocking: false + enabled: true + num_consumers: 10 + queue_size: 1000 + sizer: {} + wait_for_result: false + timeout: 30s + traces_endpoint: "" + write_buffer_size: 524288 + otlphttp/metrics: + auth: + authenticator: agenthealth/opentelemetry_metrics + compression: gzip + encoding: proto + idle_conn_timeout: 1m30s + logs_endpoint: "" + max_idle_conns: 100 + metrics_endpoint: https://monitoring.us-west-2.amazonaws.com/v1/metrics + retry_on_failure: + enabled: true + initial_interval: 5s + max_elapsed_time: 5m0s + max_interval: 30s + multiplier: 1.5 + randomization_factor: 0.5 + sending_queue: + block_on_overflow: false + blocking: false + enabled: true + num_consumers: 10 + queue_size: 1000 + sizer: {} + wait_for_result: false + timeout: 30s + traces_endpoint: "" + write_buffer_size: 524288 +extensions: + agenthealth/opentelemetry_logs: + additional_auth: headers_setter/logs + is_usage_data_enabled: true + stats: + operations: + - '*' + usage_flags: + mode: EC2 + region_type: ACJ + agenthealth/opentelemetry_metrics: + additional_auth: sigv4auth/monitoring + is_usage_data_enabled: true + stats: + operations: + - '*' + usage_flags: + mode: EC2 + region_type: ACJ + awscloudwatchlogsprovisioner: + additional_auth: sigv4auth/logs + imds_retries: 1 + logs_provision_failure_backoff: 5s + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 10 + headers_setter/logs: + additional_auth: awscloudwatchlogsprovisioner + headers: + - action: upsert + from_context: aws.log.group.name + key: x-aws-log-group + - action: upsert + from_context: aws.log.stream.name + key: x-aws-log-stream + sigv4auth/logs: + assume_role: {} + imds_retries: 1 + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 30 + service: logs + sigv4auth/monitoring: + assume_role: {} + imds_retries: 1 + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 30 + service: monitoring +processors: + attributestocontext/opentelemetry: + actions: + - from_resource_attribute: aws.log.group.name + key: aws.log.group.name + - from_resource_attribute: aws.log.stream.name + key: aws.log.stream.name + batch/opentelemetry_logs: + metadata_cardinality_limit: 1000 + metadata_keys: + - aws.log.group.name + - aws.log.stream.name + send_batch_max_size: 10000 + send_batch_size: 10000 + timeout: 30s + batch/opentelemetry_metrics: + metadata_cardinality_limit: 1000 + send_batch_max_size: 1000 + send_batch_size: 1000 + timeout: 30s + filter/dbi_exclude_monitor_sqlserver_0: + error_mode: propagate + logs: + log_record: + - attributes["user.name"] == "cw_monitor" + metrics: {} + spans: {} + traces: {} + groupbyattrs/files: + keys: + - log.file.name + resourcedetection/opentelemetry: + aks: + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + k8s.cluster.name: + enabled: false + azure: + resource_attributes: + azure.resourcegroup.name: + enabled: true + azure.vm.name: + enabled: true + azure.vm.scaleset.name: + enabled: true + azure.vm.size: + enabled: true + cloud.account.id: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + tags: [] + consul: + address: "" + datacenter: "" + namespace: "" + resource_attributes: + cloud.region: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + token_file: "" + detectors: + - eks + - env + - ec2 + docker: + resource_attributes: + host.name: + enabled: true + os.type: + enabled: true + ec2: + fail_on_missing_metadata: false + max_attempts: 3 + max_backoff: 20s + resource_attributes: + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + host.id: + enabled: true + host.image.id: + enabled: true + host.name: + enabled: true + host.type: + enabled: true + tags: + - ^kubernetes.io/cluster/.*$ + - ^aws:autoscaling:groupName + ecs: + resource_attributes: + aws.ecs.cluster.arn: + enabled: true + aws.ecs.launchtype: + enabled: true + aws.ecs.task.arn: + enabled: true + aws.ecs.task.family: + enabled: true + aws.ecs.task.id: + enabled: true + aws.ecs.task.revision: + enabled: true + aws.log.group.arns: + enabled: true + aws.log.group.names: + enabled: true + aws.log.stream.arns: + enabled: true + aws.log.stream.names: + enabled: true + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + eks: + resource_attributes: + cloud.account.id: + enabled: false + cloud.platform: + enabled: true + cloud.provider: + enabled: true + k8s.cluster.name: + enabled: false + elasticbeanstalk: + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + deployment.environment: + enabled: true + service.instance.id: + enabled: true + service.version: + enabled: true + gcp: + resource_attributes: + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + faas.id: + enabled: true + faas.instance: + enabled: true + faas.name: + enabled: true + faas.version: + enabled: true + gcp.cloud_run.job.execution: + enabled: true + gcp.cloud_run.job.task_index: + enabled: true + gcp.gce.instance.hostname: + enabled: false + gcp.gce.instance.name: + enabled: false + gcp.gce.instance_group_manager.name: + enabled: true + gcp.gce.instance_group_manager.region: + enabled: true + gcp.gce.instance_group_manager.zone: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + host.type: + enabled: true + k8s.cluster.name: + enabled: true + heroku: + resource_attributes: + cloud.provider: + enabled: true + heroku.app.id: + enabled: true + heroku.dyno.id: + enabled: true + heroku.release.commit: + enabled: true + heroku.release.creation_timestamp: + enabled: true + service.instance.id: + enabled: true + service.name: + enabled: true + service.version: + enabled: true + idle_conn_timeout: 1m30s + k8snode: + auth_type: serviceAccount + context: "" + kube_config_path: "" + node_from_env_var: "" + resource_attributes: + k8s.node.name: + enabled: true + k8s.node.uid: + enabled: true + kubeadm: + auth_type: serviceAccount + context: "" + kube_config_path: "" + resource_attributes: + k8s.cluster.name: + enabled: true + k8s.cluster.uid: + enabled: true + lambda: + resource_attributes: + aws.log.group.names: + enabled: true + aws.log.stream.names: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + faas.instance: + enabled: true + faas.max_memory: + enabled: true + faas.name: + enabled: true + faas.version: + enabled: true + max_idle_conns: 100 + openshift: + address: "" + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + k8s.cluster.name: + enabled: true + tls: {} + token: "" + override: true + system: + resource_attributes: + host.arch: + enabled: false + host.cpu.cache.l2.size: + enabled: false + host.cpu.family: + enabled: false + host.cpu.model.id: + enabled: false + host.cpu.model.name: + enabled: false + host.cpu.stepping: + enabled: false + host.cpu.vendor.id: + enabled: false + host.id: + enabled: false + host.ip: + enabled: false + host.mac: + enabled: false + host.name: + enabled: true + os.description: + enabled: false + os.type: + enabled: true + os.version: + enabled: false + timeout: 2s + transform/dbi_fix_start_time_sqlserver: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: datapoint + error_mode: ignore + statements: + - set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0 + - replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU") + - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") + - replace_match(datapoint.attributes["user.name"], "", "unknown") + trace_statements: [] + transform/dbi_logs_sqlserver_raw-events_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/raw-events") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "pentest-sqlserver"], "/")) + metric_statements: [] + trace_statements: [] + transform/dbi_logs_sqlserver_server-logs_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/server-logs") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "pentest-sqlserver"], "/")) + - context: log + error_mode: ignore + statements: + - delete_key(attributes, "timestamp") + - delete_key(attributes, "severity") + metric_statements: [] + trace_statements: [] + transform/dbi_resource_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "pentest-sqlserver") + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "pentest-sqlserver") + trace_statements: [] + transform/dbi_scope_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + trace_statements: [] + transform/host_metrics_scope: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-host-metrics") + trace_statements: [] + transform/identity: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + trace_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + transform/logs_cleanup: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - delete_key(resource.attributes, "aws.log.group.name") + - delete_key(resource.attributes, "aws.log.stream.name") + - delete_key(resource.attributes, "aws.log.source") + metric_statements: [] + trace_statements: [] + transform/logs_routing: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], Concat(["/aws/cwagent", resource.attributes["aws.log.source"]], "/")) where resource.attributes["aws.log.group.name"] == nil and resource.attributes["aws.log.source"] != nil + - set(resource.attributes["aws.log.group.name"], "/aws/cwagent/default") where resource.attributes["aws.log.group.name"] == nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["log.file.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["aws.log.source"] == "files" and resource.attributes["host.id"] != nil and resource.attributes["log.file.name"] != nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["log.file.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["aws.log.source"] == "files" and resource.attributes["host.name"] != nil and resource.attributes["log.file.name"] != nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["service.namespace"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil and resource.attributes["service.namespace"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["service.namespace"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil and resource.attributes["service.namespace"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], resource.attributes["host.id"]) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil + - set(resource.attributes["aws.log.stream.name"], resource.attributes["host.name"]) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil + - set(resource.attributes["aws.log.stream.name"], "default") where resource.attributes["aws.log.stream.name"] == nil + metric_statements: [] + trace_statements: [] +receivers: + filelog/sqlserver_0: + encoding: utf-8 + include: + - /var/opt/mssql/log/errorlog + multiline: + line_start_pattern: ^\d{4}-\d{2}-\d{2} + operators: + - regex: (?P\d{4}-\s{0,1}\d{1,2}-\s{0,1}\d{1,2} \d{2}:\d{2}:\d{2}\.(\d{1,9})) + timestamp: + layout: 2006-1-_2 15:04:05.999999999 + layout_type: gotime + location: UTC + parse_from: attributes.timestamp + type: regex_parser + - on_error: send_quiet + regex: 'Error: \d+, Severity: (?P\d+), State: \d+' + severity: + mapping: + error: + - max: 19 + min: 17 + fatal: + - max: 25 + min: 20 + info: + - max: 10 + min: 0 + warn: + - max: 16 + min: 11 + parse_from: attributes.severity + type: regex_parser + start_at: end + hostmetrics/opentelemetry: + collection_interval: 30s + initial_delay: 1s + scrapers: + cpu: + metrics: + system.cpu.frequency: + enabled: true + system.cpu.logical.count: + enabled: true + system.cpu.physical.count: + enabled: true + system.cpu.utilization: + enabled: true + disk: null + filesystem: + metrics: + system.filesystem.utilization: + enabled: true + load: null + memory: + metrics: + system.linux.memory.available: + enabled: true + system.linux.memory.dirty: + enabled: true + system.memory.limit: + enabled: true + system.memory.page_size: + enabled: true + system.memory.utilization: + enabled: true + network: null + process: + include: + match_type: regexp + names: + - sqlservr.* + metrics: + process.cpu.utilization: + enabled: true + process.memory.utilization: + enabled: true + process.threads: + enabled: true + mute_process_all_errors: true + processes: null + timeout: 0s + sqlserver/events_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor + sqlserver/metrics_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor +service: + extensions: + - sigv4auth/monitoring + - agenthealth/opentelemetry_metrics + - sigv4auth/logs + - awscloudwatchlogsprovisioner + - headers_setter/logs + - agenthealth/opentelemetry_logs + pipelines: + logs/dbi_sqlserver_0: + exporters: + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + receivers: + - sqlserver/metrics_0 + logs/dbi_sqlserver_rawevents_0: + exporters: + - forward/opentelemetry + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_raw-events_0 + receivers: + - sqlserver/events_0 + logs/dbi_sqlserver_serverlogs_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - groupbyattrs/files + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_server-logs_0 + receivers: + - filelog/sqlserver_0 + logs/opentelemetry: + exporters: + - otlphttp/logs + processors: + - resourcedetection/opentelemetry + - transform/identity + - transform/logs_routing + - attributestocontext/opentelemetry + - transform/logs_cleanup + - batch/opentelemetry_logs + receivers: + - forward/opentelemetry + metrics/dbi_sqlserver_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - transform/dbi_resource_sqlserver_0 + - transform/dbi_fix_start_time_sqlserver + receivers: + - sqlserver/metrics_0 + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + metrics/host_metrics: + exporters: + - forward/opentelemetry + processors: + - transform/host_metrics_scope + receivers: + - hostmetrics/opentelemetry + metrics/opentelemetry: + exporters: + - otlphttp/metrics + processors: + - resourcedetection/opentelemetry + - transform/identity + - batch/opentelemetry_metrics + receivers: + - forward/opentelemetry + telemetry: + logs: + encoding: console + level: info + output_paths: + - /opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log + sampling: + enabled: true + initial: 2 + thereafter: 500 + tick: 10s + metrics: + level: None + traces: + level: None diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/testdata/.sqlserver_credentials b/translator/tocwconfig/sampleConfig/opentelemetry/testdata/.sqlserver_credentials new file mode 100644 index 00000000000..9d7b4558321 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -0,0 +1 @@ +server=localhost;port=1433;user id=cw_monitor;password=test_password diff --git a/translator/translate/otel/receiver/sqlserver/translator.go b/translator/translate/otel/receiver/sqlserver/translator.go new file mode 100644 index 00000000000..f4f70bb6260 --- /dev/null +++ b/translator/translate/otel/receiver/sqlserver/translator.go @@ -0,0 +1,135 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package sqlserver + +import ( + "strconv" + "strings" + "time" + + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver" + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap" + "go.opentelemetry.io/collector/receiver" + + "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/common" +) + +type Option func(*translator) + +type translator struct { + factory receiver.Factory + name string + endpoint string + username string + passfile string + index int + topQueryInterval time.Duration +} + +func WithName(name string) Option { return func(t *translator) { t.name = name } } +func WithEndpoint(ep string) Option { return func(t *translator) { t.endpoint = ep } } +func WithUsername(u string) Option { return func(t *translator) { t.username = u } } +func WithPassfile(p string) Option { return func(t *translator) { t.passfile = p } } +func WithIndex(i int) Option { return func(t *translator) { t.index = i } } +func WithTopQueryInterval(d time.Duration) Option { + return func(t *translator) { t.topQueryInterval = d } +} + +func NewTranslator(opts ...Option) common.ComponentTranslator { + t := &translator{ + factory: sqlserverreceiver.NewFactory(), + name: "metrics", + topQueryInterval: 60 * time.Second, + } + for _, opt := range opts { + opt(t) + } + return t +} + +func (t *translator) ID() component.ID { + return component.MustNewIDWithName("sqlserver", t.name+"_"+strconv.Itoa(t.index)) +} + +// splitEndpoint splits "host:port" into server + port, defaulting to 1433. +func splitEndpoint(endpoint string) (string, uint) { + host, port := endpoint, uint(1433) + if i := strings.LastIndex(endpoint, ":"); i >= 0 { + host = endpoint[:i] + if p, err := strconv.ParseUint(endpoint[i+1:], 10, 32); err == nil { + port = uint(p) + } + } + return host, port +} + +func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { + cfg := t.factory.CreateDefaultConfig().(*sqlserverreceiver.Config) + + cfg.Server, cfg.Port = splitEndpoint(t.endpoint) + cfg.Username = t.username + cfg.Passfile = t.passfile + + // Enable metrics disabled-by-default in the receiver but required by DBI. + // These metrics align with RDS SQL Server monitoring best practices. + + // Performance & Resource Metrics (RDS equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverProcessesBlocked.Enabled = true // RDS: BlockedTransactions + cfg.MetricsBuilderConfig.Metrics.SqlserverDeadlockRate.Enabled = true // RDS: Deadlocks/sec + cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryGrantsPendingCount.Enabled = true // RDS: Memory Grants Pending + cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryUsage.Enabled = true // RDS: FreeableMemory (inverse) + + // Page & Buffer Pool Metrics (RDS equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverPageLookupRate.Enabled = true // RDS: Page Lookups/sec + cfg.MetricsBuilderConfig.Metrics.SqlserverForwardedRecordsRate.Enabled = true // Performance tuning metric + cfg.MetricsBuilderConfig.Metrics.SqlserverPageBufferCacheFreeListStallsRate.Enabled = true // Memory pressure indicator + + // Wait Statistics (RDS Performance Insights equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverLatchWaitRate.Enabled = true // Concurrency metric + cfg.MetricsBuilderConfig.Metrics.SqlserverLockTimeoutRate.Enabled = true // Lock contention + cfg.MetricsBuilderConfig.Metrics.SqlserverLockWaitCount.Enabled = true // Lock contention + + // Transaction & Log Metrics (RDS equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionActiveCount.Enabled = true // RDS: Active Transactions + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushRate.Enabled = true // RDS: Log Flushes/sec + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushWaitRate.Enabled = true // Log IO bottleneck + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogUsage.Enabled = true // RDS: TransactionLogUsage + + // Database I/O Metrics (RDS: ReadIOPS, WriteIOPS, ReadThroughput, WriteThroughput equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIo.Enabled = true // Per-database I/O + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseLatency.Enabled = true // Per-database latency + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseOperations.Enabled = true // I/O operations + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIoStallQueued.Enabled = true // Resource Governor I/O queue wait time + + // Connection & Workload Metrics (RDS equivalents) + cfg.MetricsBuilderConfig.Metrics.SqlserverLoginRate.Enabled = true // RDS: LoginFailures (partial) + cfg.MetricsBuilderConfig.Metrics.SqlserverLogoutRate.Enabled = true // Connection churn + cfg.MetricsBuilderConfig.Metrics.SqlserverSessionCount.Enabled = true // Active sessions by state + + // Index & Query Performance Metrics + cfg.MetricsBuilderConfig.Metrics.SqlserverIndexSearchRate.Enabled = true // Index usage + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseFullScanRate.Enabled = true // Table scan indicator (performance issue) + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseExecutionErrors.Enabled = true // RDS: Errors/sec + + // Optional: TempDB Metrics (useful for workload analysis) + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbSpace.Enabled = true // TempDB space usage + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbVersionStoreSize.Enabled = true // Version store size + + cfg.LogsBuilderConfig.Events.DbServerQuerySample.Enabled = true + cfg.LogsBuilderConfig.Events.DbServerTopQuery.Enabled = true + + cfg.QuerySample.MaxRowsPerQuery = 500 + cfg.TopQueryCollection.CollectionInterval = t.topQueryInterval + cfg.TopQueryCollection.TopQueryCount = 200 + cfg.TopQueryCollection.MaxQuerySampleCount = 5000 + + // Query Plan Caching: Controls caching behavior for SQL Server XML ShowPlan data + // Plans are automatically compressed (always-on) to fit within CloudWatch Logs 1MB limit + cfg.TopQueryCollection.QueryPlanCacheSize = 1000 // Cache up to 1000 plans + cfg.TopQueryCollection.QueryPlanCacheTTL = time.Hour // Keep plans for 1 hour + cfg.TopQueryCollection.MaxQueryPlanSize = 921600 // Max 900KB after compression (safety limit) + + return cfg, nil +} diff --git a/translator/translate/otel/receiver/sqlserver/translator_test.go b/translator/translate/otel/receiver/sqlserver/translator_test.go new file mode 100644 index 00000000000..e16b3de4f6a --- /dev/null +++ b/translator/translate/otel/receiver/sqlserver/translator_test.go @@ -0,0 +1,153 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +// DROP-IN LOCATION (amazon-cloudwatch-agent repo): +// translator/translate/otel/receiver/sqlserver/translator_test.go +// +// This is a TDD spec: it defines the exact behavior the SQL Server receiver +// translator must produce. Implement translator.go in the same package so this +// test passes. It mirrors receiver/mysql/translator_test.go, adapted for the +// sqlserverreceiver Config (Server+Port instead of Endpoint; QuerySample instead +// of QuerySampleCollection). + +package sqlserver + +import ( + "testing" + "time" + + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTranslator_ID(t *testing.T) { + tr := NewTranslator(WithName("metrics"), WithIndex(0)) + assert.Equal(t, "sqlserver/metrics_0", tr.ID().String()) + + tr = NewTranslator(WithName("events"), WithIndex(1)) + assert.Equal(t, "sqlserver/events_1", tr.ID().String()) +} + +func TestTranslator_Translate_Localhost(t *testing.T) { + tr := NewTranslator( + WithEndpoint("localhost:1433"), + WithUsername("cw_monitor"), + WithPassfile("/opt/databaseinsights/.sqlserver_credentials"), + WithIndex(0), + ) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + c := cfg.(*sqlserverreceiver.Config) + + // Connection: endpoint "host:port" is split into Server + Port. + assert.Equal(t, "localhost", c.Server) + assert.Equal(t, uint(1433), c.Port) + assert.Equal(t, "cw_monitor", c.Username) + assert.Equal(t, "/opt/databaseinsights/.sqlserver_credentials", c.Passfile) + assert.Empty(t, string(c.Password)) // passfile is used, never an inline password + assert.Empty(t, c.DataSource) // never combine datasource with discrete fields + + // DBI requires the two log events. + assert.True(t, c.LogsBuilderConfig.Events.DbServerQuerySample.Enabled) + assert.True(t, c.LogsBuilderConfig.Events.DbServerTopQuery.Enabled) + + // DB Load / Top SQL tuning (match the mysql translator's values). + assert.Equal(t, uint64(500), c.QuerySample.MaxRowsPerQuery) + assert.Equal(t, uint(200), c.TopQueryCollection.TopQueryCount) + assert.Equal(t, uint(5000), c.TopQueryCollection.MaxQuerySampleCount) + assert.Equal(t, 60*time.Second, c.TopQueryCollection.CollectionInterval) + + // Query Plan Caching: verify all 3 fields (compression is always-on in receiver). + assert.Equal(t, 1000, c.TopQueryCollection.QueryPlanCacheSize) + assert.Equal(t, time.Hour, c.TopQueryCollection.QueryPlanCacheTTL) + assert.Equal(t, 921600, c.TopQueryCollection.MaxQueryPlanSize) // 900KB default + + // Metrics that are disabled-by-default in the receiver but required for DBI + // console parity with RDS Performance Insights. + m := c.MetricsBuilderConfig.Metrics + + // Performance & Resource Metrics (RDS equivalents) + assert.True(t, m.SqlserverProcessesBlocked.Enabled) // RDS: BlockedTransactions + assert.True(t, m.SqlserverDeadlockRate.Enabled) // RDS: Deadlocks/sec + assert.True(t, m.SqlserverMemoryGrantsPendingCount.Enabled) // RDS: Memory Grants Pending + assert.True(t, m.SqlserverMemoryUsage.Enabled) // RDS: FreeableMemory (inverse) + + // Page & Buffer Pool Metrics (RDS equivalents) + assert.True(t, m.SqlserverPageLookupRate.Enabled) // RDS: Page Lookups/sec + assert.True(t, m.SqlserverForwardedRecordsRate.Enabled) // Performance tuning metric + assert.True(t, m.SqlserverPageBufferCacheFreeListStallsRate.Enabled) // Memory pressure indicator + + // Wait Statistics (RDS Performance Insights equivalents) + assert.True(t, m.SqlserverLatchWaitRate.Enabled) // Concurrency metric + assert.True(t, m.SqlserverLockTimeoutRate.Enabled) // Lock contention + assert.True(t, m.SqlserverLockWaitCount.Enabled) // Lock contention + + // Transaction & Log Metrics (RDS equivalents) + assert.True(t, m.SqlserverTransactionActiveCount.Enabled) // RDS: Active Transactions + assert.True(t, m.SqlserverTransactionLogFlushRate.Enabled) // RDS: Log Flushes/sec + assert.True(t, m.SqlserverTransactionLogFlushWaitRate.Enabled) // Log IO bottleneck + assert.True(t, m.SqlserverTransactionLogUsage.Enabled) // RDS: TransactionLogUsage + + // Database I/O Metrics (RDS: ReadIOPS, WriteIOPS, ReadThroughput, WriteThroughput equivalents) + assert.True(t, m.SqlserverDatabaseIo.Enabled) // Per-database I/O + assert.True(t, m.SqlserverDatabaseLatency.Enabled) // Per-database latency + assert.True(t, m.SqlserverDatabaseOperations.Enabled) // I/O operations + assert.True(t, m.SqlserverDatabaseIoStallQueued.Enabled) // Resource Governor I/O queue wait time + + // Connection & Workload Metrics (RDS equivalents) + assert.True(t, m.SqlserverLoginRate.Enabled) // RDS: LoginFailures (partial) + assert.True(t, m.SqlserverLogoutRate.Enabled) // Connection churn + assert.True(t, m.SqlserverSessionCount.Enabled) // Active sessions by state + + // Index & Query Performance Metrics + assert.True(t, m.SqlserverIndexSearchRate.Enabled) // Index usage + assert.True(t, m.SqlserverDatabaseFullScanRate.Enabled) // Table scan indicator (performance issue) + assert.True(t, m.SqlserverDatabaseExecutionErrors.Enabled) // RDS: Errors/sec + + // Optional: TempDB Metrics (useful for workload analysis) + assert.True(t, m.SqlserverDatabaseTempdbSpace.Enabled) // TempDB space usage + assert.True(t, m.SqlserverDatabaseTempdbVersionStoreSize.Enabled) // Version store size +} + +func TestTranslator_Translate_DefaultPort(t *testing.T) { + // An endpoint with no port must default to 1433. + tr := NewTranslator(WithEndpoint("localhost"), WithUsername("cw_monitor")) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + c := cfg.(*sqlserverreceiver.Config) + assert.Equal(t, "localhost", c.Server) + assert.Equal(t, uint(1433), c.Port) +} + +func TestTranslator_Translate_CustomInterval(t *testing.T) { + tr := NewTranslator( + WithEndpoint("localhost:1433"), + WithUsername("cw_monitor"), + WithTopQueryInterval(30*time.Second), + ) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + assert.Equal(t, 30*time.Second, cfg.(*sqlserverreceiver.Config).TopQueryCollection.CollectionInterval) +} + +func TestTranslator_QueryPlanCachingDefaults(t *testing.T) { + // Verify that query plan caching is configured with correct defaults. + // These 3 fields control resource usage and safety limits. + // NOTE: Compression is always-on in the receiver (not configurable). + tr := NewTranslator( + WithEndpoint("localhost:1433"), + WithUsername("cw_monitor"), + ) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + c := cfg.(*sqlserverreceiver.Config) + + // Verify the 3 query plan caching fields + assert.Equal(t, 1000, c.TopQueryCollection.QueryPlanCacheSize, + "Default cache size should be 1000 plans") + assert.Equal(t, time.Hour, c.TopQueryCollection.QueryPlanCacheTTL, + "Default cache TTL should be 1 hour") + assert.Equal(t, 921600, c.TopQueryCollection.MaxQueryPlanSize, + "Default max plan size should be 900KB (921600 bytes) after compression") +} From b22f81cd2859a9713e8502947904104b813e3e3e Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:38:05 +0000 Subject: [PATCH 02/12] feat(dbi): configure SQL Server DBI pipeline and connectors - Fix console detection: set db.system.name in resource attributes - Fix query sample filter: use false for SQL Server/MySQL - Add DB Load connector configuration (7 metrics) - Add Top SQL signal-to-metrics connector - Add transform processor for start time fix - Configure full DBI metrics pipeline DB Load metrics: - active_sessions.count (total sessions) - active_sessions.by_wait (by wait type) - active_sessions.by_user (by username) - active_sessions.by_db (by database) - active_sessions.by_sql (by SQL hash) - active_sessions.by_sql_wait (by SQL + wait) - active_sessions.by_host (by host) Fixes: - Console now detects SQL Server instances correctly - Query samples flow to CloudWatch Logs --- .../connector/count/dbi_dbload_sqlserver.yaml | 56 ++++++++++ .../otel/connector/count/translator.go | 5 + .../otel/connector/count/translator_test.go | 20 ++++ .../signaltometrics/dbi_topsql_sqlserver.yaml | 105 ++++++++++++++++++ .../connector/signaltometrics/translator.go | 5 + .../signaltometrics/translator_test.go | 21 ++++ .../databaseinsights/translator.go | 48 +++++++- .../databaseinsights/translator_test.go | 75 +++++++++++++ .../databaseinsights/translators.go | 32 ++++++ .../databaseinsights/translators_test.go | 76 +++++++++++++ ...ransform_dbi_fix_start_time_sqlserver.yaml | 10 ++ .../transformprocessor/translator.go | 5 + .../transformprocessor/translator_test.go | 15 +++ 13 files changed, 471 insertions(+), 2 deletions(-) create mode 100644 translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml create mode 100644 translator/translate/otel/connector/signaltometrics/dbi_topsql_sqlserver.yaml create mode 100644 translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml diff --git a/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml b/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml new file mode 100644 index 00000000000..91a69efe50f --- /dev/null +++ b/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml @@ -0,0 +1,56 @@ +logs: + sqlserver.active_sessions.by_wait: + description: "Active sessions by wait category" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: sqlserver.wait_category + - key: db.namespace + sqlserver.active_sessions.by_user: + description: "Active sessions by user" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: user.name + - key: db.namespace + sqlserver.active_sessions.by_db: + description: "Active sessions by database" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: db.namespace + sqlserver.active_sessions.by_sql: + description: "Active sessions by query hash" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: db.namespace + sqlserver.active_sessions.by_sql_wait: + description: "Active sessions by query and wait category" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.wait_category + - key: db.namespace + sqlserver.active_sessions.by_host: + description: "Active sessions by host" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: network.peer.address + - key: db.namespace + sqlserver.active_sessions.count: + description: "Total active sessions" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: db.namespace diff --git a/translator/translate/otel/connector/count/translator.go b/translator/translate/otel/connector/count/translator.go index 1ab0e54c0e4..1ca44cfd46c 100644 --- a/translator/translate/otel/connector/count/translator.go +++ b/translator/translate/otel/connector/count/translator.go @@ -21,6 +21,9 @@ var dbiDbloadConfig string //go:embed dbi_dbload_mysql.yaml var dbiDbloadMysqlConfig string +//go:embed dbi_dbload_sqlserver.yaml +var dbiDbloadSqlServerConfig string + type translator struct { name string engine string @@ -51,6 +54,8 @@ func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { return common.GetYamlFileToYamlConfig(cfg, dbiDbloadConfig) case common.MySQLKey: return common.GetYamlFileToYamlConfig(cfg, dbiDbloadMysqlConfig) + case common.SQLServerKey: + return common.GetYamlFileToYamlConfig(cfg, dbiDbloadSqlServerConfig) } return nil, fmt.Errorf("unsupported count connector engine: %s", t.engine) diff --git a/translator/translate/otel/connector/count/translator_test.go b/translator/translate/otel/connector/count/translator_test.go index 275af49dd61..e2952d9949a 100644 --- a/translator/translate/otel/connector/count/translator_test.go +++ b/translator/translate/otel/connector/count/translator_test.go @@ -61,3 +61,23 @@ func TestTranslateDbloadMysql(t *testing.T) { assert.Contains(t, countCfg.Logs, "mysql.active_sessions.by_host") assert.Contains(t, countCfg.Logs, "mysql.active_sessions.count") } + +func TestTranslatorID_SqlServer(t *testing.T) { + tr := NewTranslator(common.DbiConnectorDbload+"_"+common.SQLServerKey, common.SQLServerKey) + assert.Equal(t, "count/dbi_dbload_sqlserver", tr.ID().String()) +} + +func TestTranslateDbloadSqlServer(t *testing.T) { + tr := NewTranslator(common.DbiConnectorDbload+"_"+common.SQLServerKey, common.SQLServerKey) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + countCfg := cfg.(*countconnector.Config) + assert.Len(t, countCfg.Logs, 7) + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_wait") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_user") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_db") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_sql") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_sql_wait") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_host") + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.count") +} diff --git a/translator/translate/otel/connector/signaltometrics/dbi_topsql_sqlserver.yaml b/translator/translate/otel/connector/signaltometrics/dbi_topsql_sqlserver.yaml new file mode 100644 index 00000000000..1df7dd0a616 --- /dev/null +++ b/translator/translate/otel/connector/signaltometrics/dbi_topsql_sqlserver.yaml @@ -0,0 +1,105 @@ +logs: + - name: sqlserver.execution_count + include_resource_attributes: + - key: service.instance.id + description: "Number of executions" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.execution_count"] != nil + sum: + value: 'Int(attributes["sqlserver.execution_count"])' + - name: sqlserver.total_elapsed_time + include_resource_attributes: + - key: service.instance.id + description: "Total elapsed time (seconds)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_elapsed_time"] != nil + sum: + value: 'Double(attributes["sqlserver.total_elapsed_time"])' + - name: sqlserver.total_worker_time + include_resource_attributes: + - key: service.instance.id + description: "Total CPU (worker) time (seconds)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_worker_time"] != nil + sum: + value: 'Double(attributes["sqlserver.total_worker_time"])' + - name: sqlserver.total_logical_reads + include_resource_attributes: + - key: service.instance.id + description: "Total logical reads (pages)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_logical_reads"] != nil + sum: + value: 'Int(attributes["sqlserver.total_logical_reads"])' + - name: sqlserver.total_logical_writes + include_resource_attributes: + - key: service.instance.id + description: "Total logical writes (pages)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_logical_writes"] != nil + sum: + value: 'Int(attributes["sqlserver.total_logical_writes"])' + - name: sqlserver.total_physical_reads + include_resource_attributes: + - key: service.instance.id + description: "Total physical reads (pages)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_physical_reads"] != nil + sum: + value: 'Int(attributes["sqlserver.total_physical_reads"])' + - name: sqlserver.total_rows + include_resource_attributes: + - key: service.instance.id + description: "Total rows returned" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_rows"] != nil + sum: + value: 'Int(attributes["sqlserver.total_rows"])' + - name: sqlserver.total_grant_kb + include_resource_attributes: + - key: service.instance.id + description: "Total memory grant (KB)" + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.query_plan_hash + - key: db.namespace + conditions: + - attributes["sqlserver.total_grant_kb"] != nil + sum: + value: 'Int(attributes["sqlserver.total_grant_kb"])' diff --git a/translator/translate/otel/connector/signaltometrics/translator.go b/translator/translate/otel/connector/signaltometrics/translator.go index a26fbe4870f..dcd7c750d33 100644 --- a/translator/translate/otel/connector/signaltometrics/translator.go +++ b/translator/translate/otel/connector/signaltometrics/translator.go @@ -22,6 +22,9 @@ var dbiTopsqlConfig string //go:embed dbi_topsql_mysql.yaml var dbiTopsqlMysqlConfig string +//go:embed dbi_topsql_sqlserver.yaml +var dbiTopsqlSqlServerConfig string + type translator struct { name string engine string @@ -52,6 +55,8 @@ func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { return common.GetYamlFileToYamlConfig(cfg, dbiTopsqlConfig) case common.MySQLKey: return common.GetYamlFileToYamlConfig(cfg, dbiTopsqlMysqlConfig) + case common.SQLServerKey: + return common.GetYamlFileToYamlConfig(cfg, dbiTopsqlSqlServerConfig) } return nil, fmt.Errorf("unsupported signaltometrics connector engine: %s", t.engine) diff --git a/translator/translate/otel/connector/signaltometrics/translator_test.go b/translator/translate/otel/connector/signaltometrics/translator_test.go index 6515b90bba6..0db1421eadb 100644 --- a/translator/translate/otel/connector/signaltometrics/translator_test.go +++ b/translator/translate/otel/connector/signaltometrics/translator_test.go @@ -72,3 +72,24 @@ func TestTranslateTopsqlMysql(t *testing.T) { assert.Equal(t, "mysql.sum_sort_merge_passes", stmCfg.Logs[16].Name) assert.Equal(t, "mysql.sum_sort_range", stmCfg.Logs[17].Name) } + +func TestTranslatorID_SqlServer(t *testing.T) { + tr := NewTranslator(common.DbiConnectorTopsql+"_"+common.SQLServerKey, common.SQLServerKey) + assert.Equal(t, "signaltometrics/dbi_topsql_sqlserver", tr.ID().String()) +} + +func TestTranslateTopsqlSqlServer(t *testing.T) { + tr := NewTranslator(common.DbiConnectorTopsql+"_"+common.SQLServerKey, common.SQLServerKey) + cfg, err := tr.Translate(nil) + require.NoError(t, err) + stmCfg := cfg.(*signaltometricsconfig.Config) + assert.Len(t, stmCfg.Logs, 8) + assert.Equal(t, "sqlserver.execution_count", stmCfg.Logs[0].Name) + assert.Equal(t, "sqlserver.total_elapsed_time", stmCfg.Logs[1].Name) + assert.Equal(t, "sqlserver.total_worker_time", stmCfg.Logs[2].Name) + assert.Equal(t, "sqlserver.total_logical_reads", stmCfg.Logs[3].Name) + assert.Equal(t, "sqlserver.total_logical_writes", stmCfg.Logs[4].Name) + assert.Equal(t, "sqlserver.total_physical_reads", stmCfg.Logs[5].Name) + assert.Equal(t, "sqlserver.total_rows", stmCfg.Logs[6].Name) + assert.Equal(t, "sqlserver.total_grant_kb", stmCfg.Logs[7].Name) +} diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go index 7fa62343961..83dcc236f8c 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go @@ -24,6 +24,7 @@ import ( "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/receiver/filelog" "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/receiver/mysql" "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/receiver/postgresql" + "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/receiver/sqlserver" ) type dbiPipelineType int @@ -84,6 +85,25 @@ func buildMysqlSeverityPattern() string { return `\s\d+\s+\[(?P` + strings.Join(mysqlLogSeverityLevels, "|") + `)\]` } +// sqlserverLogSeverityMapping maps SQL Server error-log severity numbers to OTEL +// severity levels. SQL Server severities run 0-25: 0-10 informational, 11-16 user +// errors, 17-19 resource/software errors, 20-25 fatal. Ranges are used so every +// numeric severity maps without enumerating all 26 values. Lines without an +// "Error: ..., Severity: ..." prefix (most startup/informational messages) simply +// do not match and pass through with the default severity. +var sqlserverLogSeverityMapping = map[string]any{ + "info": []any{map[string]any{"min": 0, "max": 10}}, + "warn": []any{map[string]any{"min": 11, "max": 16}}, + "error": []any{map[string]any{"min": 17, "max": 19}}, + "fatal": []any{map[string]any{"min": 20, "max": 25}}, +} + +// buildSqlServerSeverityPattern builds the regex that extracts the severity number from +// a SQL Server error-log line of the form "Error: , Severity: , State: ". +func buildSqlServerSeverityPattern() string { + return `Error: \d+, Severity: (?P\d+), State: \d+` +} + // dbiTranslator generates DBI pipelines for a single database instance. The // engine (carried on cfg) selects engine-specific receivers, connector configs, // resource attributes, and log group paths. Component IDs are index-based so @@ -255,6 +275,14 @@ func (t *dbiTranslator) serverLogReceiver() common.ComponentTranslator { filelog.WithSeverityPattern(buildMysqlSeverityPattern()), filelog.WithSeverityMapping(mysqlLogSeverityMapping), ) + case common.SQLServerKey: + // SQL Server error log timestamps are "2026-07-20 15:27:47.12" (UTC when the + // instance is configured with -T or an ADO connection in UTC). + opts = append(opts, + filelog.WithTimestampFormat("%Y-%m-%d %H:%M:%S.%f", "UTC"), + filelog.WithSeverityPattern(buildSqlServerSeverityPattern()), + filelog.WithSeverityMapping(sqlserverLogSeverityMapping), + ) } return filelog.NewTranslator(opts...) } @@ -272,6 +300,16 @@ func (t *dbiTranslator) receiver(name string) common.ComponentTranslator { ) } + if t.cfg.engine == common.SQLServerKey { + return sqlserver.NewTranslator( + sqlserver.WithName(name), + sqlserver.WithIndex(t.instanceIndex), + sqlserver.WithEndpoint(t.cfg.endpoint), + sqlserver.WithUsername(t.cfg.username), + sqlserver.WithPassfile(t.cfg.passfile), + ) + } + opts := []postgresql.Option{ postgresql.WithName(name), postgresql.WithIndex(t.instanceIndex), @@ -289,10 +327,16 @@ func (t *dbiTranslator) receiver(name string) common.ComponentTranslator { func (t *dbiTranslator) excludeMonitorFilter() common.ComponentTranslator { idx := strconv.Itoa(t.instanceIndex) - condition := fmt.Sprintf(`attributes["user.name"] == "%s"`, t.cfg.username) + + // SQL Server already filters out the monitoring session in the query itself if t.cfg.engine == common.PostgreSQLKey { - condition = fmt.Sprintf(`attributes["user.name"] == "%s" or attributes["postgresql.rolname"] == "%s"`, t.cfg.username, t.cfg.username) + condition := fmt.Sprintf(`attributes["user.name"] == "%s" or attributes["postgresql.rolname"] == "%s"`, t.cfg.username, t.cfg.username) + return filterprocessor.NewTranslatorWithLogCondition(common.DbiFilterExcludeMonitor+"_"+t.cfg.engine+"_"+idx, condition, common.OTTLErrorModePropagate) } + + // For MySQL and SQL Server, use a filter that always passes (matches nothing) + // This allows all query samples through since the receivers already filter correctly + condition := `false` // Never matches, so nothing gets filtered return filterprocessor.NewTranslatorWithLogCondition(common.DbiFilterExcludeMonitor+"_"+t.cfg.engine+"_"+idx, condition, common.OTTLErrorModePropagate) } diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator_test.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator_test.go index 3aa3c345d4a..0a05428d1b1 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator_test.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator_test.go @@ -32,6 +32,11 @@ func TestDbiTranslatorID(t *testing.T) { {"Mysql_LogToMetrics_0", common.MySQLKey, dbiLogToMetrics, 0, "logs/dbi_mysql_0"}, {"Mysql_RawEvents_0", common.MySQLKey, dbiRawEvents, 0, "logs/dbi_mysql_rawevents_0"}, {"Mysql_ServerLogs_0", common.MySQLKey, dbiServerLogs, 0, "logs/dbi_mysql_serverlogs_0"}, + {"SqlServer_Metrics_0", common.SQLServerKey, dbiMetrics, 0, "metrics/dbi_sqlserver_0"}, + {"SqlServer_Metrics_1", common.SQLServerKey, dbiMetrics, 1, "metrics/dbi_sqlserver_1"}, + {"SqlServer_LogToMetrics_0", common.SQLServerKey, dbiLogToMetrics, 0, "logs/dbi_sqlserver_0"}, + {"SqlServer_RawEvents_0", common.SQLServerKey, dbiRawEvents, 0, "logs/dbi_sqlserver_rawevents_0"}, + {"SqlServer_ServerLogs_0", common.SQLServerKey, dbiServerLogs, 0, "logs/dbi_sqlserver_serverlogs_0"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { @@ -181,6 +186,76 @@ func TestDbiMysqlTranslateMetrics_ComponentIDs(t *testing.T) { assert.ElementsMatch(t, []string{"forward/opentelemetry", "count/dbi_dbload_mysql", "signaltometrics/dbi_topsql_mysql"}, connectors) } +func TestDbiSqlServerTranslate(t *testing.T) { + cfg := dbiInstanceConfig{ //nolint:gosec + engine: common.SQLServerKey, + endpoint: "localhost:1433", + username: "cw_monitor", + passfile: "/etc/.sqlserver_credentials", + instanceName: "my-db", + logFilePath: "/var/opt/mssql/log/errorlog", + isLocalhost: true, + } + + tests := []struct { + name string + pipeline dbiPipelineType + expectedID string + nRecv int + nProc int + nExp int + nConn int + }{ + {"metrics", dbiMetrics, "metrics/dbi_sqlserver_0", 3, 3, 1, 3}, + {"log_to_metrics", dbiLogToMetrics, "logs/dbi_sqlserver_0", 1, 1, 2, 2}, + {"raw_events", dbiRawEvents, "logs/dbi_sqlserver_rawevents_0", 1, 5, 1, 1}, + {"server_logs", dbiServerLogs, "logs/dbi_sqlserver_serverlogs_0", 1, 5, 1, 1}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tr := &dbiTranslator{pipelineType: tc.pipeline, instanceIndex: 0, cfg: cfg} + assert.Equal(t, tc.expectedID, tr.ID().String()) + + result, err := tr.Translate(nil) + require.NoError(t, err) + assert.Equal(t, tc.nRecv, result.Receivers.Len()) + assert.Equal(t, tc.nProc, result.Processors.Len()) + assert.Equal(t, tc.nExp, result.Exporters.Len()) + assert.Equal(t, tc.nConn, result.Connectors.Len()) + }) + } +} + +func TestDbiSqlServerTranslateMetrics_ComponentIDs(t *testing.T) { + tr := &dbiTranslator{ + pipelineType: dbiMetrics, + instanceIndex: 0, + cfg: dbiInstanceConfig{engine: common.SQLServerKey, instanceName: "mydb"}, + } + result, err := tr.Translate(nil) + require.NoError(t, err) + + var receivers, processors, exporters, connectors []string + result.Receivers.Range(func(c common.Translator[component.Config, component.ID]) { + receivers = append(receivers, c.ID().String()) + }) + result.Processors.Range(func(c common.Translator[component.Config, component.ID]) { + processors = append(processors, c.ID().String()) + }) + result.Exporters.Range(func(c common.Translator[component.Config, component.ID]) { + exporters = append(exporters, c.ID().String()) + }) + result.Connectors.Range(func(c common.Translator[component.Config, component.ID]) { + connectors = append(connectors, c.ID().String()) + }) + + assert.ElementsMatch(t, []string{"sqlserver/metrics_0", "count/dbi_dbload_sqlserver", "signaltometrics/dbi_topsql_sqlserver"}, receivers) + assert.Equal(t, []string{"transform/dbi_scope_sqlserver_0", "transform/dbi_resource_sqlserver_0", "transform/dbi_fix_start_time_sqlserver"}, processors) + assert.ElementsMatch(t, []string{"forward/opentelemetry"}, exporters) + assert.ElementsMatch(t, []string{"forward/opentelemetry", "count/dbi_dbload_sqlserver", "signaltometrics/dbi_topsql_sqlserver"}, connectors) +} + func TestDbiTranslateServerLogs_FilelogConfig(t *testing.T) { cfg := dbiInstanceConfig{ //nolint:gosec engine: common.PostgreSQLKey, diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators.go index 7d6c9a66a60..de136340d55 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators.go @@ -51,6 +51,7 @@ func NewTranslators(conf *confmap.Conf) common.PipelineTranslatorMap { addInstances(parseDbiPostgresqlInstances(conf)) addInstances(parseDbiMysqlInstances(conf)) + addInstances(parseDbiSqlServerInstances(conf)) return translators } @@ -129,6 +130,37 @@ func parseDbiMysqlInstances(conf *confmap.Conf) []dbiInstanceConfig { return instances } +type sqlServerRawInstance struct { + Endpoint string `mapstructure:"endpoint"` + Username string `mapstructure:"username"` + PasswordFile string `mapstructure:"password_file"` + InstanceName string `mapstructure:"instance_name"` + Logs struct { + FilePath string `mapstructure:"file_path"` + } `mapstructure:"logs"` +} + +func parseDbiSqlServerInstances(conf *confmap.Conf) []dbiInstanceConfig { + arr, _ := conf.Get(common.DatabaseInsightsSqlServerKey).([]any) + var raw []sqlServerRawInstance + if err := mapstructure.Decode(arr, &raw); err != nil { + return nil + } + instances := make([]dbiInstanceConfig, 0, len(raw)) + for _, r := range raw { + instances = append(instances, dbiInstanceConfig{ + engine: common.SQLServerKey, + endpoint: r.Endpoint, + username: r.Username, + passfile: r.PasswordFile, + instanceName: r.InstanceName, + logFilePath: r.Logs.FilePath, + isLocalhost: isLocalhostEndpoint(r.Endpoint), + }) + } + return instances +} + func isLocalhostEndpoint(endpoint string) bool { return strings.HasPrefix(endpoint, "localhost") || strings.HasPrefix(endpoint, "127.0.0.1") || diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators_test.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators_test.go index f6afa300f61..fc17f8c3d2d 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators_test.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translators_test.go @@ -189,3 +189,79 @@ func TestNewTranslators_MySQL_MultiInstance(t *testing.T) { } assert.ElementsMatch(t, expected, ids) } + +func TestNewTranslators_SqlServer_WithLogs(t *testing.T) { + cfg := confmap.NewFromStringMap(map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "sqlserver": []interface{}{ + map[string]interface{}{ //nolint:gosec + "endpoint": "localhost:1433", "username": "cw_monitor", + "password_file": "/opt/databaseinsights/.sqlserver_credentials", "instance_name": "my-db", + "logs": map[string]interface{}{"file_path": "/var/opt/mssql/log/errorlog"}, + }, + }, + }, + }, + }, + }) + assert.Equal(t, 4, NewTranslators(cfg).Len()) +} + +func TestNewTranslators_SqlServer_NoLogs(t *testing.T) { + cfg := confmap.NewFromStringMap(map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "sqlserver": []interface{}{ + map[string]interface{}{ //nolint:gosec + "endpoint": "localhost:1433", "username": "cw_monitor", + "password_file": "/opt/databaseinsights/.sqlserver_credentials", "instance_name": "my-db", + }, + }, + }, + }, + }, + }) + assert.Equal(t, 3, NewTranslators(cfg).Len()) +} + +func TestNewTranslators_SqlServer_MultiInstance(t *testing.T) { + cfg := confmap.NewFromStringMap(map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "sqlserver": []interface{}{ + map[string]interface{}{ //nolint:gosec + "endpoint": "localhost:1433", "username": "cw_monitor", + "password_file": "/opt/databaseinsights/.sqlserver_credentials", "instance_name": "db1", + "logs": map[string]interface{}{"file_path": "/var/opt/mssql/log/errorlog1"}, + }, + map[string]interface{}{ //nolint:gosec + "endpoint": "db2.example.com:1433", "username": "monitor", + "password_file": "/opt/databaseinsights/.sqlserver_credentials2", "instance_name": "db2", + }, + }, + }, + }, + }, + }) + translators := NewTranslators(cfg) + assert.Equal(t, 7, translators.Len()) // 4 + 3 + + var ids []string + for _, k := range translators.Keys() { + ids = append(ids, k.String()) + } + expected := []string{ + "metrics/dbi_sqlserver_0", + "logs/dbi_sqlserver_0", + "logs/dbi_sqlserver_rawevents_0", + "logs/dbi_sqlserver_serverlogs_0", + "metrics/dbi_sqlserver_1", + "logs/dbi_sqlserver_1", + "logs/dbi_sqlserver_rawevents_1", + } + assert.ElementsMatch(t, expected, ids) +} diff --git a/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml b/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml new file mode 100644 index 00000000000..01c63552ab6 --- /dev/null +++ b/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml @@ -0,0 +1,10 @@ +error_mode: ignore +metric_statements: + - context: datapoint + error_mode: ignore + statements: + - set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0 + - replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU") + - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") + - replace_match(datapoint.attributes["user.name"], "", "unknown") diff --git a/translator/translate/otel/processor/transformprocessor/translator.go b/translator/translate/otel/processor/transformprocessor/translator.go index ff3c513c4d5..6fecee97249 100644 --- a/translator/translate/otel/processor/transformprocessor/translator.go +++ b/translator/translate/otel/processor/transformprocessor/translator.go @@ -35,6 +35,9 @@ var transformDbiFixStartTimeConfig string //go:embed transform_dbi_fix_start_time_mysql.yaml var transformDbiFixStartTimeMysqlConfig string +//go:embed transform_dbi_fix_start_time_sqlserver.yaml +var transformDbiFixStartTimeSqlServerConfig string + //go:embed transform_identity_ec2.yaml var transformIdentityEC2Config string @@ -215,6 +218,8 @@ func (t *translator) Translate(conf *confmap.Conf) (component.Config, error) { return common.GetYamlFileToYamlConfig(cfg, transformDbiFixStartTimeConfig) case common.MySQLKey: return common.GetYamlFileToYamlConfig(cfg, transformDbiFixStartTimeMysqlConfig) + case common.SQLServerKey: + return common.GetYamlFileToYamlConfig(cfg, transformDbiFixStartTimeSqlServerConfig) } return nil, fmt.Errorf("unsupported dbi fix-start-time engine: %s", t.dbiFixStartTimeEngine) } diff --git a/translator/translate/otel/processor/transformprocessor/translator_test.go b/translator/translate/otel/processor/transformprocessor/translator_test.go index 5e1e2f84cca..0a664c42e64 100644 --- a/translator/translate/otel/processor/transformprocessor/translator_test.go +++ b/translator/translate/otel/processor/transformprocessor/translator_test.go @@ -108,6 +108,21 @@ func TestDbiFixStartTimeMysqlTranslate(t *testing.T) { assert.Equal(t, `replace_match(datapoint.attributes["user.name"], "", "unknown")`, actualCfg.MetricStatements[0].Statements[4]) } +func TestDbiFixStartTimeSqlServerTranslate(t *testing.T) { + transl := NewTranslatorWithName(common.DbiTransformFixStartTime+"_"+common.SQLServerKey, WithDbiFixStartTime(common.SQLServerKey)) + assert.Equal(t, "transform/dbi_fix_start_time_sqlserver", transl.ID().String()) + + cfg, err := transl.Translate(nil) + require.NoError(t, err) + actualCfg := cfg.(*transformprocessor.Config) + require.Len(t, actualCfg.MetricStatements, 1) + assert.Equal(t, "datapoint", string(actualCfg.MetricStatements[0].Context)) + require.Len(t, actualCfg.MetricStatements[0].Statements, 5) + assert.Equal(t, "set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0", actualCfg.MetricStatements[0].Statements[0]) + assert.Equal(t, `replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU")`, actualCfg.MetricStatements[0].Statements[1]) + assert.Equal(t, `replace_match(datapoint.attributes["user.name"], "", "unknown")`, actualCfg.MetricStatements[0].Statements[4]) +} + func TestDbiResourceTranslate(t *testing.T) { stmts := []string{ `set(resource.attributes["db.system.name"], "postgresql")`, From d8c2f4b7fda39951ca08d06aed3c5202771ce017 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:41:12 +0000 Subject: [PATCH 03/12] feat(dbi): register SQL Server components Component Registration: - Register SQL Server receiver in default components - Update common component utilities - Update configuration schema - Add platform-specific tests Changes: - Add sqlserverreceiver to default receiver list - Update component factory to include SQL Server - Add SQL Server to configuration validation - Add test coverage for new components --- service/defaultcomponents/components.go | 2 ++ service/defaultcomponents/components_test.go | 1 + translator/config/schema.json | 21 +++++++++++++++++++ translator/tocwconfig/tocwconfig_unix_test.go | 8 +++++++ translator/translate/otel/common/common.go | 16 +++++++------- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/service/defaultcomponents/components.go b/service/defaultcomponents/components.go index c5f324597b8..d9d1cccfffb 100644 --- a/service/defaultcomponents/components.go +++ b/service/defaultcomponents/components.go @@ -58,6 +58,7 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/postgresqlreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/statsdreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/tcplogreceiver" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/udplogreceiver" @@ -122,6 +123,7 @@ func Factories() (otelcol.Factories, error) { prometheusreceiver.NewFactory(), mysqlreceiver.NewFactory(), postgresqlreceiver.NewFactory(), + sqlserverreceiver.NewFactory(), statsdreceiver.NewFactory(), systemmetricsreceiver.NewFactory(), tcplogreceiver.NewFactory(), diff --git a/service/defaultcomponents/components_test.go b/service/defaultcomponents/components_test.go index 6cefe44c516..1745c4c0376 100644 --- a/service/defaultcomponents/components_test.go +++ b/service/defaultcomponents/components_test.go @@ -37,6 +37,7 @@ func TestComponents(t *testing.T) { "prometheus", "mysql", "postgresql", + "sqlserver", "statsd", "systemmetrics", "tcplog", diff --git a/translator/config/schema.json b/translator/config/schema.json index db2c693a154..11358eda7b9 100644 --- a/translator/config/schema.json +++ b/translator/config/schema.json @@ -1868,6 +1868,27 @@ "required": ["endpoint", "instance_name", "username", "password_file"], "additionalProperties": false } + }, + "sqlserver": { + "type": "array", + "items": { + "type": "object", + "properties": { + "endpoint": { "type": "string" }, + "instance_name": { "type": "string" }, + "username": { "type": "string" }, + "password_file": { "type": "string" }, + "logs": { + "type": "object", + "properties": { + "file_path": { "type": "string" } + }, + "additionalProperties": false + } + }, + "required": ["endpoint", "instance_name", "username", "password_file"], + "additionalProperties": false + } } }, "additionalProperties": false diff --git a/translator/tocwconfig/tocwconfig_unix_test.go b/translator/tocwconfig/tocwconfig_unix_test.go index 1f2230c01f4..8328cc3f4a7 100644 --- a/translator/tocwconfig/tocwconfig_unix_test.go +++ b/translator/tocwconfig/tocwconfig_unix_test.go @@ -196,6 +196,14 @@ func TestDBIMySQLConfigLinux(t *testing.T) { checkTranslation(t, "opentelemetry/dbi_mysql_config_linux", "linux", expectedEnvVars, "") } +func TestDBISqlServerConfigLinux(t *testing.T) { + resetContext(t) + context.CurrentContext().SetMode(config.ModeEC2) + require.NoError(t, os.Chmod("sampleConfig/opentelemetry/testdata/.sqlserver_credentials", 0600)) + expectedEnvVars := map[string]string{} + checkTranslation(t, "opentelemetry/dbi_sqlserver_config_linux", "linux", expectedEnvVars, "") +} + func TestDefaultOtelConfigAzureVMTranslation(t *testing.T) { resetContext(t) context.CurrentContext().SetMode(config.ModeAzureVM) diff --git a/translator/translate/otel/common/common.go b/translator/translate/otel/common/common.go index 6a741c0dc06..d5d8df2d322 100644 --- a/translator/translate/otel/common/common.go +++ b/translator/translate/otel/common/common.go @@ -148,6 +148,7 @@ const ( DatabaseInsightsKey = "database_insights" PostgreSQLKey = "postgresql" MySQLKey = "mysql" + SQLServerKey = "sqlserver" // DBI component name prefixes (shared across engines; index-suffixed per instance) DbiTransformFixStartTime = "dbi_fix_start_time" @@ -165,13 +166,14 @@ const ( ) var ( - DatabaseInsightsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey) - DatabaseInsightsPostgresKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey, PostgreSQLKey) - DatabaseInsightsMysqlKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey, MySQLKey) - OtelCollectLogsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, LogsKey) - OtelSpanMetricsEnabledKey = ConfigKey(OpenTelemetryKey, CollectKey, OtlpKey, "span_metrics_enabled") - WindowsEventsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, WindowsEventsKey) - FilesConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, FilesKey) + DatabaseInsightsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey) + DatabaseInsightsPostgresKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey, PostgreSQLKey) + DatabaseInsightsMysqlKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey, MySQLKey) + DatabaseInsightsSqlServerKey = ConfigKey(OpenTelemetryKey, CollectKey, DatabaseInsightsKey, SQLServerKey) + OtelCollectLogsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, LogsKey) + OtelSpanMetricsEnabledKey = ConfigKey(OpenTelemetryKey, CollectKey, OtlpKey, "span_metrics_enabled") + WindowsEventsConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, WindowsEventsKey) + FilesConfigKey = ConfigKey(OpenTelemetryKey, CollectKey, FilesKey) // OtelResourceAttributesKey holds customer-supplied resource attributes added to every opentelemetry export pipeline. OtelResourceAttributesKey = ConfigKey(OpenTelemetryKey, ResourceAttributesKey) ) From 350dbec63768b05fb623591cabeb1cdc922a8c16 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:41:29 +0000 Subject: [PATCH 04/12] feat(dbi): update sample configs and dependencies for SQL Server - Add SQL Server DBI to combined EC2 sample configs - Add SQL Server DBI to combined EKS sample configs - Update go.mod/go.sum with SQL Server receiver dependencies - Use local receiver via replace directive for development Configuration examples show: - SQL Server endpoint (localhost:1433) - Monitoring user credentials (passfile) - Instance naming - Integration with other DBI engines (PostgreSQL, MySQL) --- go.mod | 40 +- go.sum | 102 +-- .../combined_v1_v2_ec2_config.json | 11 + .../combined_v1_v2_ec2_config.yaml | 751 ++++++++++++++++- .../combined_v1_v2_eks_config.json | 11 + .../combined_v1_v2_eks_config.yaml | 753 +++++++++++++++++- 6 files changed, 1594 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index 43005818efe..ff59cebfbdf 100644 --- a/go.mod +++ b/go.mod @@ -72,6 +72,7 @@ replace ( github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260723202011-09a6da50bc48 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/postgresqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd + github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver => /home/larkirs/workplace/opentelemetry-collector-contrib/receiver/sqlserverreceiver // Cherry-pick of upstream Query XML support for windowseventlogreceiver https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/39055 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowseventlogreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/windowseventlogreceiver v0.0.0-20260717191209-ee093fbfffbd ) @@ -217,7 +218,7 @@ require ( github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1 github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil/v3 v3.24.5 - github.com/shirou/gopsutil/v4 v4.25.3 + github.com/shirou/gopsutil/v4 v4.26.3 github.com/stretchr/testify v1.11.1 github.com/xeipuuv/gojsonschema v1.2.0 go.opentelemetry.io/collector/client v1.30.0 @@ -278,7 +279,7 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 gopkg.in/yaml.v3 v3.0.1 - gotest.tools/v3 v3.2.0 + gotest.tools/v3 v3.5.2 k8s.io/api v0.32.3 k8s.io/apimachinery v0.32.3 k8s.io/client-go v0.32.3 @@ -288,17 +289,21 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.3 // indirect - github.com/DataDog/datadog-go/v5 v5.6.0 // indirect - github.com/DataDog/go-sqllexer v0.1.3 // indirect + github.com/DataDog/datadog-go/v5 v5.8.3 // indirect + github.com/DataDog/go-sqllexer v0.1.12 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.29 // indirect github.com/aws/aws-sdk-go-v2/service/s3 v1.53.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/lib/pq v1.12.3 // indirect + github.com/microsoft/go-mssqldb v1.9.6 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/internal/sqlquery v0.124.1 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters v0.124.1 // indirect github.com/outcaste-io/ristretto v0.2.3 // indirect + github.com/shopspring/decimal v1.4.0 // indirect modernc.org/sqlite v1.29.6 // indirect ) @@ -308,14 +313,14 @@ require ( cloud.google.com/go/compute/metadata v0.9.0 // indirect collectd.org v0.4.0 // indirect github.com/Azure/azure-sdk-for-go v67.1.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0 // indirect github.com/Azure/go-autorest/autorest v0.11.29 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect github.com/Code-Hex/go-generics-cache v1.5.1 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 // indirect github.com/IBM/sarama v1.45.1 // indirect @@ -381,13 +386,13 @@ require ( github.com/digitalocean/godo v1.136.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.3.3+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/doclambda/protobufquery v0.0.0-20210317203640-88ffabe06a60 // indirect github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/ebitengine/purego v0.8.4 // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/edsrzf/mmap-go v1.2.0 // indirect github.com/elastic/go-grok v0.3.1 // indirect github.com/elastic/lunes v0.1.0 // indirect @@ -478,7 +483,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect github.com/karrick/godirwalk v1.17.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.5 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect github.com/kr/text v0.2.0 // indirect @@ -490,7 +495,7 @@ require ( github.com/linode/linodego v1.47.0 // indirect github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect github.com/magefile/mage v1.15.0 // indirect - github.com/magiconair/properties v1.8.9 // indirect + github.com/magiconair/properties v1.8.10 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -541,6 +546,7 @@ require ( github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheus v0.124.1 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite v0.124.1 // indirect github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.124.1 // indirect + github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver v0.124.1 github.com/opencontainers/cgroups v0.0.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect @@ -555,7 +561,7 @@ require ( github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/alertmanager v0.28.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common/assets v0.2.0 // indirect @@ -569,11 +575,11 @@ require ( github.com/rs/cors v1.11.1 // indirect github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32 // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.4 // indirect github.com/sleepinggenius2/gosmi v0.4.4 // indirect github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect - github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/objx v0.5.3 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect @@ -581,8 +587,8 @@ require ( github.com/tidwall/wal v1.1.8 // indirect github.com/tilinna/clock v1.1.0 // indirect github.com/tinylib/msgp v1.1.6 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twmb/murmur3 v1.1.8 // indirect github.com/ua-parser/uap-go v0.0.0-20240611065828-3a4781585db6 // indirect diff --git a/go.sum b/go.sum index ae2f501448b..088cc685a61 100644 --- a/go.sum +++ b/go.sum @@ -48,8 +48,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= code.cloudfoundry.org/clock v1.0.0 h1:kFXWQM4bxYvdBw2X8BbBeXwQNgfoWv1vqAk2ZZyBN2o= code.cloudfoundry.org/clock v1.0.0/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8= -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -67,14 +67,14 @@ github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVt github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-sdk-for-go v67.1.0+incompatible h1:oziYcaopbnIKfM69DL05wXdypiqfrUKdxUKrKpynJTw= github.com/Azure/azure-sdk-for-go v67.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0 h1:LkHbJbgF3YyvC53aqYGR+wWQDn2Rdp9AQdGndf9QvY4= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.7.0/go.mod h1:QyiQdW4f4/BIfB8ZutZ2s+28RAgfa/pT+zS++ZHyM1I= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= @@ -83,6 +83,10 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.3.0/go.mod h1:Y/HgrePTmGy9HjdSGTqZNa+apUpTVIEVKXJyARP2lrk= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 h1:Wgf5rZba3YZqeTNJPtvqZoBu1sBN/L4sry+u2U3Y75w= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM= @@ -123,8 +127,8 @@ github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c h1:/IBSNwUN8+eKzU github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4= -github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= @@ -138,10 +142,10 @@ github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.3 h1:hgf4Yp2MRnNnlstRh+He2pixCOwLKGQmrWLRHwM7LGI= github.com/DataDog/datadog-agent/pkg/obfuscate v0.64.3/go.mod h1:izbemZjqzBn9upkZj8SyT9igSGPMALaQYgswJ0408vY= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/datadog-go/v5 v5.6.0 h1:2oCLxjF/4htd55piM75baflj/KoE6VYS7alEUqFvRDw= -github.com/DataDog/datadog-go/v5 v5.6.0/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= -github.com/DataDog/go-sqllexer v0.1.3 h1:Kl2T6QVndMEZqQSY8rkoltYP+LVNaA54N+EwAMc9N5w= -github.com/DataDog/go-sqllexer v0.1.3/go.mod h1:KwkYhpFEVIq+BfobkTC1vfqm4gTi65skV/DpDBXtexc= +github.com/DataDog/datadog-go/v5 v5.8.3 h1:s58CUJ9s8lezjhTNJO/SxkPBv2qZjS3ktpRSqGF5n0s= +github.com/DataDog/datadog-go/v5 v5.8.3/go.mod h1:K9kcYBlxkcPP8tvvjZZKs/m1edNAUFzBbdpTUKfCsuw= +github.com/DataDog/go-sqllexer v0.1.12 h1:2eI/Mbs+fcHzXp4iwGz60V6mAWQNFOD/aa98ZluJJ7c= +github.com/DataDog/go-sqllexer v0.1.12/go.mod h1:vOw7Ia7z+z6nl3zGZlLIZe0vQlPtCPR906WIPBJadxc= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0 h1:DHa2U07rk8syqvCge0QIGMCE1WxGj9njT44GH7zNJLQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.31.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0= github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= @@ -518,8 +522,8 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/doclambda/protobufquery v0.0.0-20210317203640-88ffabe06a60 h1:27379cxrsKlr7hAnW/xrusefspUPjqHVRW1K/bZgfGw= @@ -540,8 +544,8 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= -github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y= github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= @@ -830,7 +834,9 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -1046,15 +1052,15 @@ github.com/karrick/godirwalk v1.17.0 h1:b4kY7nqDdioR/6qnbHQyDvmA17u5G1cZ6J+CZXwS github.com/karrick/godirwalk v1.17.0/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= -github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= +github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= +github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= @@ -1099,8 +1105,8 @@ github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMn github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= +github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= @@ -1138,6 +1144,8 @@ github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/microsoft/ApplicationInsights-Go v0.4.4 h1:G4+H9WNs6ygSCe6sUyxRc2U81TI5Es90b2t/MwX5KqY= github.com/microsoft/ApplicationInsights-Go v0.4.4/go.mod h1:fKRUseBqkw6bDiXTs3ESTiU/4YTIHsQS4W3fP2ieF4U= +github.com/microsoft/go-mssqldb v1.9.6 h1:1MNQg5UiSsokiPz3++K2KPx4moKrwIqly1wv+RyCKTw= +github.com/microsoft/go-mssqldb v1.9.6/go.mod h1:yYMPDufyoF2vVuVCUGtZARr06DKFIhMrluTcgWlXpr4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= @@ -1180,8 +1188,8 @@ github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= github.com/moby/ipvs v1.0.1 h1:aoZ7fhLTXgDbzVrAnvV+XbKOU8kOET7B3+xULDF/1o0= github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= -github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= -github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U= +github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= @@ -1193,8 +1201,8 @@ github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1328,6 +1336,8 @@ github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometh github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/prometheusremotewrite v0.124.1/go.mod h1:Lq8C46pYtcJKM6lbzJsM1ehg27FsO3m0ZNkLSiLnZtk= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.124.1 h1:cyvsrj/D+/XwoXSw/4FD/S1M50jco7k963f/+si907w= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/zipkin v0.124.1/go.mod h1:xAU/ievEszZYP1DGWy+yYjAjfjRCKyBLBAnXYvKWNWc= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters v0.124.1 h1:7wQVu4ep+Rj/DaNR8lpMbQb8P8WBtL+8xtSNA1RJDjo= +github.com/open-telemetry/opentelemetry-collector-contrib/pkg/winperfcounters v0.124.1/go.mod h1:PbXntQDLy3wHF2Drh2mCN05/V4HkTshgoNVttmirFJg= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/xk8stest v0.124.1 h1:jH7YOb/kClYFNo8+70ywAdweXyYeqLJvE5EoPriKun8= github.com/open-telemetry/opentelemetry-collector-contrib/pkg/xk8stest v0.124.1/go.mod h1:nWjjzGy7WQ/QntwK6dfCez419c+YATh6Heb9uKjjqp0= github.com/open-telemetry/opentelemetry-collector-contrib/processor/attributesprocessor v0.124.1 h1:nE0KSsMpcrGjZKPSxyODDOC4GrgB4py05iROSu1DttI= @@ -1447,8 +1457,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI= -github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/alertmanager v0.28.0 h1:sLN+6HhZet8hrbmGHLAHWsTXgZSVCvq9Ix3U3wvivqc= github.com/prometheus/alertmanager v0.28.0/go.mod h1:/okSnb2LlodbMlRoOWQEKtqI/coOo2NKZDm2Hu9QHLQ= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1495,8 +1505,8 @@ github.com/rabbitmq/amqp091-go v1.2.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0V github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= 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.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= -github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= +github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= +github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/relvacode/iso8601 v1.6.0 h1:eFXUhMJN3Gz8Rcq82f9DTMW0svjtAVuIEULglM7QHTU= github.com/relvacode/iso8601 v1.6.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -1525,10 +1535,12 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUt github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= -github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= +github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc= +github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= github.com/shoenig/test v1.7.1 h1:UJcjSAI3aUKx52kfcfhblgyhZceouhvvs3OYdWgn+PY= github.com/shoenig/test v1.7.1/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/showwin/speedtest-go v1.1.4 h1:pcY1W5LYZu44lH6Fuu80nu/Pj67n//VArlZudbAgR6E= github.com/showwin/speedtest-go v1.1.4/go.mod h1:dJugxvC/AQDt4HQQKZ9lKNa2+b1c8nzj9IL0a/F8l1U= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= @@ -1546,8 +1558,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/sleepinggenius2/gosmi v0.4.4 h1:xgu+Mt7CptuB10IPt3SVXBAA9tARToT4B9xGzjjxQX8= github.com/sleepinggenius2/gosmi v0.4.4/go.mod h1:l8OniPmd3bJzw0MXP2/qh7AhP/e+bTY2CNivIhsnDT0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1560,7 +1572,6 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1573,8 +1584,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4= +github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1610,11 +1622,11 @@ github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOM github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= @@ -2157,7 +2169,6 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2165,7 +2176,6 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -2437,8 +2447,8 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= -gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.json b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.json index 64d6f92bf52..843c7aee681 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.json +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.json @@ -152,6 +152,17 @@ "file_path": "/var/log/mysql/error.log" } } + ], + "sqlserver": [ + { + "endpoint": "localhost:1433", + "instance_name": "my-sqlserver", + "username": "cw_monitor", + "password_file": "sampleConfig/opentelemetry/testdata/.sqlserver_credentials", + "logs": { + "file_path": "/var/opt/mssql/log/errorlog" + } + } ] }, "prometheus": { diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml index e867d2814f4..cdeb30dd5a0 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml @@ -147,6 +147,75 @@ connectors: spans: trace.span.count: description: The number of spans observed. + count/dbi_dbload_sqlserver: + datapoints: + metric.datapoint.count: + description: The number of data points observed. + logs: + sqlserver.active_sessions.by_db: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by database + sqlserver.active_sessions.by_host: + attributes: + - key: db.system.name + - key: network.peer.address + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by host + sqlserver.active_sessions.by_sql: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query hash + sqlserver.active_sessions.by_sql_wait: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query and wait category + sqlserver.active_sessions.by_user: + attributes: + - key: db.system.name + - key: user.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by user + sqlserver.active_sessions.by_wait: + attributes: + - key: db.system.name + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by wait category + sqlserver.active_sessions.count: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Total active sessions + metrics: + metric.count: + description: The number of metrics observed. + spanevents: + trace.span.event.count: + description: The number of span events observed. + spans: + trace.span.count: + description: The number of spans observed. forward/opentelemetry: {} signaltometrics/dbi_topsql_mysql: logs: @@ -602,6 +671,144 @@ connectors: sum: value: Int(attributes["postgresql.local_blks_read"]) unit: "" + signaltometrics/dbi_topsql_sqlserver: + logs: + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.execution_count"] != nil + description: Number of executions + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.execution_count + sum: + value: Int(attributes["sqlserver.execution_count"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_elapsed_time"] != nil + description: Total elapsed time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_elapsed_time + sum: + value: Double(attributes["sqlserver.total_elapsed_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_worker_time"] != nil + description: Total CPU (worker) time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_worker_time + sum: + value: Double(attributes["sqlserver.total_worker_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_reads"] != nil + description: Total logical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_reads + sum: + value: Int(attributes["sqlserver.total_logical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_writes"] != nil + description: Total logical writes (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_writes + sum: + value: Int(attributes["sqlserver.total_logical_writes"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_physical_reads"] != nil + description: Total physical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_physical_reads + sum: + value: Int(attributes["sqlserver.total_physical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_rows"] != nil + description: Total rows returned + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_rows + sum: + value: Int(attributes["sqlserver.total_rows"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_grant_kb"] != nil + description: Total memory grant (KB) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_grant_kb + sum: + value: Int(attributes["sqlserver.total_grant_kb"]) + unit: "" exporters: awscloudwatch: backoff_retry_base: 200ms @@ -942,6 +1149,14 @@ processors: metrics: {} spans: {} traces: {} + filter/dbi_exclude_monitor_sqlserver_0: + error_mode: propagate + logs: + log_record: + - attributes["user.name"] == "cw_monitor" + metrics: {} + spans: {} + traces: {} groupbyattrs/files: keys: - log.file.name @@ -1255,6 +1470,20 @@ processors: - replace_match(datapoint.attributes["postgresql.query_id"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") trace_statements: [] + transform/dbi_fix_start_time_sqlserver: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: datapoint + error_mode: ignore + statements: + - set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0 + - replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU") + - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") + - replace_match(datapoint.attributes["user.name"], "", "unknown") + trace_statements: [] transform/dbi_logs_mysql_raw-events_0: error_mode: ignore flatten_data: false @@ -1309,6 +1538,33 @@ processors: - delete_key(attributes, "severity") metric_statements: [] trace_statements: [] + transform/dbi_logs_sqlserver_raw-events_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/raw-events") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "my-sqlserver"], "/")) + metric_statements: [] + trace_statements: [] + transform/dbi_logs_sqlserver_server-logs_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/server-logs") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "my-sqlserver"], "/")) + - context: log + error_mode: ignore + statements: + - delete_key(attributes, "timestamp") + - delete_key(attributes, "severity") + metric_statements: [] + trace_statements: [] transform/dbi_resource_mysql_0: error_mode: ignore flatten_data: false @@ -1341,6 +1597,22 @@ processors: - set(resource.attributes["db.system.name"], "postgresql") - set(resource.attributes["db.instance.name"], "my-postgres") trace_statements: [] + transform/dbi_resource_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "my-sqlserver") + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "my-sqlserver") + trace_statements: [] transform/dbi_scope_mysql_0: error_mode: ignore flatten_data: false @@ -1373,6 +1645,22 @@ processors: - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") trace_statements: [] + transform/dbi_scope_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + trace_statements: [] transform/host_metrics_scope: error_mode: ignore flatten_data: false @@ -1584,6 +1872,39 @@ receivers: parse_from: attributes.severity type: regex_parser start_at: end + filelog/sqlserver_0: + encoding: utf-8 + include: + - /var/opt/mssql/log/errorlog + multiline: + line_start_pattern: ^\d{4}-\d{2}-\d{2} + operators: + - regex: (?P\d{4}-\s{0,1}\d{1,2}-\s{0,1}\d{1,2} \d{2}:\d{2}:\d{2}\.(\d{1,9})) + timestamp: + layout: 2006-1-_2 15:04:05.999999999 + layout_type: gotime + location: UTC + parse_from: attributes.timestamp + type: regex_parser + - on_error: send_quiet + regex: 'Error: \d+, Severity: (?P\d+), State: \d+' + severity: + mapping: + error: + - max: 19 + min: 17 + fatal: + - max: 25 + min: 20 + info: + - max: 10 + min: 0 + warn: + - max: 16 + min: 11 + parse_from: attributes.severity + type: regex_parser + start_at: end hostmetrics/opentelemetry: collection_interval: 1m0s initial_delay: 1s @@ -1623,6 +1944,7 @@ receivers: names: - post(gres|master).* - mysqld.* + - sqlservr.* metrics: process.cpu.utilization: enabled: true @@ -2505,6 +2827,384 @@ receivers: start_time_metric_regex: "" trim_metric_suffixes: false use_start_time_metric: false + sqlserver/events_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor + sqlserver/metrics_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor telegraf_cpu: collection_interval: 1m0s initial_delay: 1s @@ -2641,6 +3341,36 @@ service: - transform/dbi_logs_postgresql_server-logs_0 receivers: - filelog/postgresql_0 + logs/dbi_sqlserver_0: + exporters: + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + receivers: + - sqlserver/metrics_0 + logs/dbi_sqlserver_rawevents_0: + exporters: + - forward/opentelemetry + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_raw-events_0 + receivers: + - sqlserver/events_0 + logs/dbi_sqlserver_serverlogs_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - groupbyattrs/files + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_server-logs_0 + receivers: + - filelog/sqlserver_0 logs/emf_logs: exporters: - awscloudwatchlogs/emf_logs @@ -2692,6 +3422,17 @@ service: - postgresql/metrics_0 - count/dbi_dbload_postgresql - signaltometrics/dbi_topsql_postgresql + metrics/dbi_sqlserver_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - transform/dbi_resource_sqlserver_0 + - transform/dbi_fix_start_time_sqlserver + receivers: + - sqlserver/metrics_0 + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver metrics/host: exporters: - awscloudwatch @@ -2699,13 +3440,13 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_mem - - telegraf_netstat - - telegraf_procstat/1917393364 - telegraf_swap - telegraf_processes + - telegraf_netstat - telegraf_cpu + - telegraf_mem - telegraf_disk + - telegraf_procstat/1917393364 metrics/host_metrics: exporters: - forward/opentelemetry @@ -2720,8 +3461,8 @@ service: - ec2tagger - awsentity/service/telegraf receivers: - - telegraf_socket_listener - telegraf_statsd + - telegraf_socket_listener metrics/hostDeltaMetrics: exporters: - awscloudwatch @@ -2730,8 +3471,8 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_diskio - telegraf_net + - telegraf_diskio metrics/opentelemetry: exporters: - otlphttp/metrics diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.json b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.json index 6b6928d20fb..8ef8e78d69b 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.json +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.json @@ -155,6 +155,17 @@ "file_path": "/var/log/mysql/error.log" } } + ], + "sqlserver": [ + { + "endpoint": "localhost:1433", + "instance_name": "my-sqlserver", + "username": "cw_monitor", + "password_file": "sampleConfig/opentelemetry/testdata/.sqlserver_credentials", + "logs": { + "file_path": "/var/opt/mssql/log/errorlog" + } + } ] }, "prometheus": { diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml index d4c60736372..e93223067be 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml @@ -147,6 +147,75 @@ connectors: spans: trace.span.count: description: The number of spans observed. + count/dbi_dbload_sqlserver: + datapoints: + metric.datapoint.count: + description: The number of data points observed. + logs: + sqlserver.active_sessions.by_db: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by database + sqlserver.active_sessions.by_host: + attributes: + - key: db.system.name + - key: network.peer.address + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by host + sqlserver.active_sessions.by_sql: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query hash + sqlserver.active_sessions.by_sql_wait: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query and wait category + sqlserver.active_sessions.by_user: + attributes: + - key: db.system.name + - key: user.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by user + sqlserver.active_sessions.by_wait: + attributes: + - key: db.system.name + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by wait category + sqlserver.active_sessions.count: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Total active sessions + metrics: + metric.count: + description: The number of metrics observed. + spanevents: + trace.span.event.count: + description: The number of span events observed. + spans: + trace.span.count: + description: The number of spans observed. forward/opentelemetry: {} signaltometrics/dbi_topsql_mysql: logs: @@ -602,6 +671,144 @@ connectors: sum: value: Int(attributes["postgresql.local_blks_read"]) unit: "" + signaltometrics/dbi_topsql_sqlserver: + logs: + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.execution_count"] != nil + description: Number of executions + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.execution_count + sum: + value: Int(attributes["sqlserver.execution_count"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_elapsed_time"] != nil + description: Total elapsed time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_elapsed_time + sum: + value: Double(attributes["sqlserver.total_elapsed_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_worker_time"] != nil + description: Total CPU (worker) time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_worker_time + sum: + value: Double(attributes["sqlserver.total_worker_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_reads"] != nil + description: Total logical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_reads + sum: + value: Int(attributes["sqlserver.total_logical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_logical_writes"] != nil + description: Total logical writes (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_writes + sum: + value: Int(attributes["sqlserver.total_logical_writes"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_physical_reads"] != nil + description: Total physical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_physical_reads + sum: + value: Int(attributes["sqlserver.total_physical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_rows"] != nil + description: Total rows returned + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_rows + sum: + value: Int(attributes["sqlserver.total_rows"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + conditions: + - attributes["sqlserver.total_grant_kb"] != nil + description: Total memory grant (KB) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_grant_kb + sum: + value: Int(attributes["sqlserver.total_grant_kb"]) + unit: "" exporters: awscloudwatch: backoff_retry_base: 200ms @@ -1010,6 +1217,14 @@ processors: metrics: {} spans: {} traces: {} + filter/dbi_exclude_monitor_sqlserver_0: + error_mode: propagate + logs: + log_record: + - attributes["user.name"] == "cw_monitor" + metrics: {} + spans: {} + traces: {} groupbyattrs/cw_k8s_ci_v0_cadvisor: keys: - container @@ -1688,6 +1903,20 @@ processors: - replace_match(datapoint.attributes["postgresql.query_id"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") trace_statements: [] + transform/dbi_fix_start_time_sqlserver: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: datapoint + error_mode: ignore + statements: + - set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0 + - replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU") + - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") + - replace_match(datapoint.attributes["user.name"], "", "unknown") + trace_statements: [] transform/dbi_logs_mysql_raw-events_0: error_mode: ignore flatten_data: false @@ -1742,6 +1971,33 @@ processors: - delete_key(attributes, "severity") metric_statements: [] trace_statements: [] + transform/dbi_logs_sqlserver_raw-events_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/raw-events") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "my-sqlserver"], "/")) + metric_statements: [] + trace_statements: [] + transform/dbi_logs_sqlserver_server-logs_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/server-logs") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "my-sqlserver"], "/")) + - context: log + error_mode: ignore + statements: + - delete_key(attributes, "timestamp") + - delete_key(attributes, "severity") + metric_statements: [] + trace_statements: [] transform/dbi_resource_mysql_0: error_mode: ignore flatten_data: false @@ -1774,6 +2030,22 @@ processors: - set(resource.attributes["db.system.name"], "postgresql") - set(resource.attributes["db.instance.name"], "my-postgres") trace_statements: [] + transform/dbi_resource_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "my-sqlserver") + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "my-sqlserver") + trace_statements: [] transform/dbi_scope_mysql_0: error_mode: ignore flatten_data: false @@ -1806,6 +2078,22 @@ processors: - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") trace_statements: [] + transform/dbi_scope_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + trace_statements: [] transform/host_metrics_scope: error_mode: ignore flatten_data: false @@ -2117,6 +2405,39 @@ receivers: parse_from: attributes.severity type: regex_parser start_at: end + filelog/sqlserver_0: + encoding: utf-8 + include: + - /var/opt/mssql/log/errorlog + multiline: + line_start_pattern: ^\d{4}-\d{2}-\d{2} + operators: + - regex: (?P\d{4}-\s{0,1}\d{1,2}-\s{0,1}\d{1,2} \d{2}:\d{2}:\d{2}\.(\d{1,9})) + timestamp: + layout: 2006-1-_2 15:04:05.999999999 + layout_type: gotime + location: UTC + parse_from: attributes.timestamp + type: regex_parser + - on_error: send_quiet + regex: 'Error: \d+, Severity: (?P\d+), State: \d+' + severity: + mapping: + error: + - max: 19 + min: 17 + fatal: + - max: 25 + min: 20 + info: + - max: 10 + min: 0 + warn: + - max: 16 + min: 11 + parse_from: attributes.severity + type: regex_parser + start_at: end hostmetrics/opentelemetry: collection_interval: 1m0s initial_delay: 1s @@ -2156,6 +2477,7 @@ receivers: names: - post(gres|master).* - mysqld.* + - sqlservr.* metrics: process.cpu.utilization: enabled: true @@ -3191,6 +3513,384 @@ receivers: start_time_metric_regex: "" trim_metric_suffixes: false use_start_time_metric: false + sqlserver/events_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor + sqlserver/metrics_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: false + sqlserver.database.full_scan.rate: + enabled: false + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: false + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: false + sqlserver.database.tempdb.version_store.size: + enabled: false + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: false + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: false + sqlserver.lock.wait.count: + enabled: false + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: false + sqlserver.logout.rate: + enabled: false + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: false + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: false + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: true + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_sample_count: 5000 + top_query_count: 200 + username: cw_monitor telegraf_cpu: collection_interval: 1m0s initial_delay: 1s @@ -3328,6 +4028,36 @@ service: - transform/dbi_logs_postgresql_server-logs_0 receivers: - filelog/postgresql_0 + logs/dbi_sqlserver_0: + exporters: + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + receivers: + - sqlserver/metrics_0 + logs/dbi_sqlserver_rawevents_0: + exporters: + - forward/opentelemetry + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_raw-events_0 + receivers: + - sqlserver/events_0 + logs/dbi_sqlserver_serverlogs_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - groupbyattrs/files + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_server-logs_0 + receivers: + - filelog/sqlserver_0 logs/emf_logs: exporters: - awscloudwatchlogs/emf_logs @@ -3548,6 +4278,17 @@ service: - postgresql/metrics_0 - count/dbi_dbload_postgresql - signaltometrics/dbi_topsql_postgresql + metrics/dbi_sqlserver_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - transform/dbi_resource_sqlserver_0 + - transform/dbi_fix_start_time_sqlserver + receivers: + - sqlserver/metrics_0 + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver metrics/host: exporters: - awscloudwatch @@ -3555,13 +4296,13 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_mem - - telegraf_procstat/1917393364 - - telegraf_cpu - telegraf_processes - - telegraf_disk - telegraf_netstat + - telegraf_cpu - telegraf_swap + - telegraf_disk + - telegraf_procstat/1917393364 + - telegraf_mem metrics/host_metrics: exporters: - forward/opentelemetry @@ -3576,8 +4317,8 @@ service: - ec2tagger - awsentity/service/telegraf receivers: - - telegraf_socket_listener - telegraf_statsd + - telegraf_socket_listener metrics/hostDeltaMetrics: exporters: - awscloudwatch @@ -3586,8 +4327,8 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_diskio - telegraf_net + - telegraf_diskio metrics/opentelemetry: exporters: - otlphttp/metrics From 06d91e7b8b5698a2a40845fe432dfb4b767f1c04 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:43:02 +0000 Subject: [PATCH 05/12] feat(detector): add SQL Server detector for workload discovery SQL Server Detector: - Detects SQL Server process (sqlservr, sqlservr.exe) - Extracts port from command line flags (-p) or environment (MSSQL_TCP_PORT) - Defaults to port 1433 - Supports custom installation paths - Platform: Linux and Windows Port Extraction: - Parses -p flag from command line arguments - Reads MSSQL_TCP_PORT environment variable - Command line takes precedence over environment - Falls back to default port 1433 Detection logic: - Searches for sqlservr process in ps output - Excludes sqlcmd (client tool, not server) - Handles both default and custom SQL Server installations - Works on Linux and Windows platforms Files: - internal/detector/sqlserver/sqlserver.go - Main detector - internal/detector/sqlserver/extract/port.go - Port extraction logic - internal/detector/metadata.go - Register SQL Server detector --- cmd/workload-discovery/discovery.go | 2 + internal/detector/metadata.go | 1 + internal/detector/sqlserver/README.md | 26 ++++ internal/detector/sqlserver/extract/port.go | 95 ++++++++++++ .../detector/sqlserver/extract/port_test.go | 77 ++++++++++ internal/detector/sqlserver/sqlserver.go | 61 ++++++++ internal/detector/sqlserver/sqlserver_test.go | 142 ++++++++++++++++++ 7 files changed, 404 insertions(+) create mode 100644 internal/detector/sqlserver/README.md create mode 100644 internal/detector/sqlserver/extract/port.go create mode 100644 internal/detector/sqlserver/extract/port_test.go create mode 100644 internal/detector/sqlserver/sqlserver.go create mode 100644 internal/detector/sqlserver/sqlserver_test.go diff --git a/cmd/workload-discovery/discovery.go b/cmd/workload-discovery/discovery.go index 7d5e1b92de9..c1c9144bdff 100644 --- a/cmd/workload-discovery/discovery.go +++ b/cmd/workload-discovery/discovery.go @@ -22,6 +22,7 @@ import ( "github.com/aws/amazon-cloudwatch-agent/internal/detector/java" "github.com/aws/amazon-cloudwatch-agent/internal/detector/mysql" "github.com/aws/amazon-cloudwatch-agent/internal/detector/nvidia" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/sqlserver" "github.com/aws/amazon-cloudwatch-agent/internal/detector/util" "github.com/aws/amazon-cloudwatch-agent/tool/paths" ) @@ -49,6 +50,7 @@ func NewDiscoverer(cfg Config, logger *slog.Logger) *Discoverer { processDetectors: []detector.ProcessDetector{ java.NewDetector(logger, filters.Process.Name), mysql.NewDetector(logger), + sqlserver.NewDetector(logger), }, deviceDetectors: []detector.DeviceDetector{ nvidia.NewDetector(logger), diff --git a/internal/detector/metadata.go b/internal/detector/metadata.go index 1e48bb4d2e1..6df55cb0f6e 100644 --- a/internal/detector/metadata.go +++ b/internal/detector/metadata.go @@ -31,6 +31,7 @@ const ( CategoryKafkaClient Category = "KAFKA/CLIENT" CategoryNvidiaGPU Category = "NVIDIA_GPU" CategoryMySQL Category = "MYSQL" + CategorySQLServer Category = "SQLSERVER" ) // Status represents whether the resource requires more actions before telemetry is available. diff --git a/internal/detector/sqlserver/README.md b/internal/detector/sqlserver/README.md new file mode 100644 index 00000000000..95ca1be7ed1 --- /dev/null +++ b/internal/detector/sqlserver/README.md @@ -0,0 +1,26 @@ +# SQL Server Process Detector + +Detects SQL Server database server processes running on the system. + +## Overview + +The SQL Server detector identifies SQL Server instances by checking for the `sqlservr` executable name. It is used by the `workload-discovery` command to automatically discover SQL Server workloads. + +## Detection Method + +The detector examines the executable path of each process and checks if the base name is `sqlservr`. + +## Status Results + +- `READY`: SQL Server process detected with a port (explicit via `-p` flag or `MSSQL_TCP_PORT`, otherwise defaults to 1433). + +## Sample Metadata Result + +```json +{ + "categories": ["SQLSERVER"], + "name": "sqlserver", + "status": "READY", + "telemetryPort": 1433 +} +``` diff --git a/internal/detector/sqlserver/extract/port.go b/internal/detector/sqlserver/extract/port.go new file mode 100644 index 00000000000..975ba1fb0fb --- /dev/null +++ b/internal/detector/sqlserver/extract/port.go @@ -0,0 +1,95 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package extract + +import ( + "context" + "strconv" + "strings" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/util" +) + +const ( + portFlagShort = "-p" + portEnvVar = "MSSQL_TCP_PORT" + defaultSQLServerPort = 1433 +) + +type portExtractor struct { + subExtractors []detector.PortExtractor +} + +// NewPortExtractor creates a port extractor that attempts to find the SQL Server port +// from command line arguments (-p flag) or environment variables (MSSQL_TCP_PORT). +// Falls back to the default SQL Server port 1433. +func NewPortExtractor() detector.PortExtractor { + return &portExtractor{ + subExtractors: []detector.PortExtractor{ + &cmdlinePortExtractor{}, + &envPortExtractor{}, + }, + } +} + +func (e *portExtractor) Extract(ctx context.Context, process detector.Process) (int, error) { + for _, sub := range e.subExtractors { + port, err := sub.Extract(ctx, process) + if err == nil { + return port, nil + } + } + return defaultSQLServerPort, nil +} + +// cmdlinePortExtractor extracts port from -p flag +type cmdlinePortExtractor struct{} + +func (e *cmdlinePortExtractor) Extract(ctx context.Context, process detector.Process) (int, error) { + args, err := process.CmdlineSliceWithContext(ctx) + if err != nil { + return 0, err + } + + for i, arg := range args { + // -p 1434 or -p1434 + if arg == portFlagShort && i+1 < len(args) { + port, err := strconv.Atoi(args[i+1]) + if err == nil && util.IsValidPort(port) { + return port, nil + } + } + if strings.HasPrefix(arg, portFlagShort) && len(arg) > len(portFlagShort) { + port, err := strconv.Atoi(arg[len(portFlagShort):]) + if err == nil && util.IsValidPort(port) { + return port, nil + } + } + } + + return 0, detector.ErrExtractPort +} + +// envPortExtractor extracts port from MSSQL_TCP_PORT environment variable +type envPortExtractor struct{} + +func (e *envPortExtractor) Extract(ctx context.Context, process detector.Process) (int, error) { + env, err := process.EnvironWithContext(ctx) + if err != nil { + return 0, err + } + + for _, entry := range env { + parts := strings.SplitN(entry, "=", 2) + if len(parts) == 2 && parts[0] == portEnvVar { + port, err := strconv.Atoi(strings.TrimSpace(parts[1])) + if err == nil && util.IsValidPort(port) { + return port, nil + } + } + } + + return 0, detector.ErrExtractPort +} diff --git a/internal/detector/sqlserver/extract/port_test.go b/internal/detector/sqlserver/extract/port_test.go new file mode 100644 index 00000000000..0b293af90c3 --- /dev/null +++ b/internal/detector/sqlserver/extract/port_test.go @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package extract + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector/detectortest" +) + +func TestPortExtractor(t *testing.T) { + ctx := context.Background() + extractor := NewPortExtractor() + + tests := map[string]struct { + setup func(*detectortest.MockProcess) + wantPort int + }{ + "Success/PortFromShortFlag": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr", "-p", "1434"}, nil) + }, + wantPort: 1434, + }, + "Success/PortFromShortFlagNoSpace": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr", "-p1435"}, nil) + }, + wantPort: 1435, + }, + "Success/PortFromEnv": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{"PATH=/usr/bin", "MSSQL_TCP_PORT=1436"}, nil) + }, + wantPort: 1436, + }, + "Success/CmdlineTakesPrecedence": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr", "-p", "1437"}, nil) + }, + wantPort: 1437, + }, + "Success/DefaultPort": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{"PATH=/usr/bin"}, nil) + }, + wantPort: 1433, + }, + "Success/DefaultOnAllSourcesFail": { + setup: func(mp *detectortest.MockProcess) { + mp.On("CmdlineSliceWithContext", ctx).Return(nil, assert.AnError) + mp.On("EnvironWithContext", ctx).Return(nil, assert.AnError) + }, + wantPort: 1433, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + mp := new(detectortest.MockProcess) + tt.setup(mp) + + port, err := extractor.Extract(ctx, mp) + + require.NoError(t, err) + assert.Equal(t, tt.wantPort, port) + mp.AssertExpectations(t) + }) + } +} diff --git a/internal/detector/sqlserver/sqlserver.go b/internal/detector/sqlserver/sqlserver.go new file mode 100644 index 00000000000..9e8b16d5706 --- /dev/null +++ b/internal/detector/sqlserver/sqlserver.go @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package sqlserver + +import ( + "context" + "log/slog" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/sqlserver/extract" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/util" +) + +const ( + exeName = "sqlservr" +) + +type sqlserverDetector struct { + logger *slog.Logger + portExtractor detector.PortExtractor +} + +var _ detector.ProcessDetector = (*sqlserverDetector)(nil) + +// NewDetector creates a new process detector that identifies SQL Server processes. +func NewDetector(logger *slog.Logger) detector.ProcessDetector { + return &sqlserverDetector{ + logger: logger, + portExtractor: extract.NewPortExtractor(), + } +} + +// Detect identifies SQL Server processes and returns metadata. +func (d *sqlserverDetector) Detect(ctx context.Context, process detector.Process) (*detector.Metadata, error) { + exe, err := process.ExeWithContext(ctx) + if err != nil { + return nil, err + } + + base := util.BaseExe(exe) + if base != exeName { + return nil, detector.ErrIncompatibleDetector + } + + d.logger.Debug("SQL Server process detected", "pid", process.PID()) + + md := &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + } + + port, err := d.portExtractor.Extract(ctx, process) + if err != nil { + return nil, err + } + md.Status = detector.StatusReady + md.TelemetryPort = port + + return md, nil +} diff --git a/internal/detector/sqlserver/sqlserver_test.go b/internal/detector/sqlserver/sqlserver_test.go new file mode 100644 index 00000000000..c22af6d3c9c --- /dev/null +++ b/internal/detector/sqlserver/sqlserver_test.go @@ -0,0 +1,142 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package sqlserver + +import ( + "context" + "log/slog" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/detectortest" +) + +func TestDetect(t *testing.T) { + ctx := context.Background() + logger := slog.Default() + d := NewDetector(logger) + + tests := map[string]struct { + setup func(*detectortest.MockProcess) + want *detector.Metadata + wantErr error + }{ + "Success/DefaultPort": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/opt/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{}, nil) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1433, + }, + }, + "Success/CustomPort": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/opt/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr", "-p", "1434"}, nil) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1434, + }, + }, + "Success/PortFromEnv": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/opt/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{"MSSQL_TCP_PORT=1435"}, nil) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1435, + }, + }, + "Success/AlternateInstallPath": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/usr/local/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{}, nil) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1433, + }, + }, + "Success/DefaultPortWithOtherFlags": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/opt/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return([]string{"sqlservr", "-d", "/var/opt/mssql/data"}, nil) + mp.On("EnvironWithContext", ctx).Return([]string{}, nil) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1433, + }, + }, + "Incompatible/NotSQLServer": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/usr/bin/postgres", nil) + }, + wantErr: detector.ErrIncompatibleDetector, + }, + "Incompatible/SQLCmd": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/usr/bin/sqlcmd", nil) + }, + wantErr: detector.ErrIncompatibleDetector, + }, + "Error/ExeWithContext": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("", assert.AnError) + }, + wantErr: assert.AnError, + }, + "Error/CmdlineSliceWithContext": { + setup: func(mp *detectortest.MockProcess) { + mp.On("ExeWithContext", ctx).Return("/opt/mssql/bin/sqlservr", nil) + mp.On("CmdlineSliceWithContext", ctx).Return(nil, assert.AnError) + mp.On("EnvironWithContext", ctx).Return(nil, assert.AnError) + }, + want: &detector.Metadata{ + Name: "sqlserver", + Categories: []detector.Category{detector.CategorySQLServer}, + Status: detector.StatusReady, + TelemetryPort: 1433, + }, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + mp := new(detectortest.MockProcess) + tt.setup(mp) + + got, err := d.Detect(ctx, mp) + + if tt.wantErr != nil { + require.ErrorIs(t, err, tt.wantErr) + assert.Nil(t, got) + } else { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + } + mp.AssertExpectations(t) + }) + } +} From 1a8207f36b707835520455dfb901d6a1a5347b2b Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Sun, 26 Jul 2026 19:47:18 +0000 Subject: [PATCH 06/12] feat(dbi): integrate SQL Server with workload discovery - Add SQL Server process scraping to hostmetrics pipeline - Configure sqlservr.* process pattern for SQL Server detection - Add merge rule tests for SQL Server database_insights config - Enable process metrics (CPU, memory, threads) for SQL Server instances --- .../opentelemetry/hostmetrics/translator.go | 3 + .../hostmetrics/translator_test.go | 36 +++++++++++ .../pipeline/opentelemetry/merge_rule_test.go | 59 +++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator.go b/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator.go index b0877c4559d..d6460bca720 100644 --- a/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator.go +++ b/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator.go @@ -45,6 +45,9 @@ func (t *hostMetricsTranslator) Translate(conf *confmap.Conf) (*common.Component if conf.IsSet(common.DatabaseInsightsMysqlKey) { processNames = append(processNames, "mysqld.*") } + if conf.IsSet(common.DatabaseInsightsSqlServerKey) { + processNames = append(processNames, "sqlservr.*") + } opts = append(opts, hostmetrics.WithProcessScraper(map[string]any{ "include": map[string]any{ "match_type": "regexp", diff --git a/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator_test.go b/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator_test.go index f0f23a2a161..32acd856c21 100644 --- a/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator_test.go +++ b/translator/translate/otel/pipeline/opentelemetry/hostmetrics/translator_test.go @@ -75,6 +75,21 @@ func TestHostMetricsTranslator(t *testing.T) { expectProcess: true, wantProcessNames: []string{"mysqld.*"}, }, + "WithSqlServerDatabaseInsightsKey": { + input: map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "sqlserver": []interface{}{ + map[string]interface{}{"endpoint": "localhost:1433", "username": "cwagent"}, + }, + }, + }, + }, + }, + expectProcess: true, + wantProcessNames: []string{"sqlservr.*"}, + }, "WithBothEngines": { input: map[string]interface{}{ "opentelemetry": map[string]interface{}{ @@ -93,6 +108,27 @@ func TestHostMetricsTranslator(t *testing.T) { expectProcess: true, wantProcessNames: []string{"post(gres|master).*", "mysqld.*"}, }, + "WithAllThreeEngines": { + input: map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "postgresql": []interface{}{ + map[string]interface{}{"endpoint": "localhost:5432", "username": "cwagent"}, + }, + "mysql": []interface{}{ + map[string]interface{}{"endpoint": "localhost:3306", "username": "cwagent"}, + }, + "sqlserver": []interface{}{ + map[string]interface{}{"endpoint": "localhost:1433", "username": "cwagent"}, + }, + }, + }, + }, + }, + expectProcess: true, + wantProcessNames: []string{"post(gres|master).*", "mysqld.*", "sqlservr.*"}, + }, "WithBothKeys": { input: map[string]interface{}{ "opentelemetry": map[string]interface{}{ diff --git a/translator/translate/otel/pipeline/opentelemetry/merge_rule_test.go b/translator/translate/otel/pipeline/opentelemetry/merge_rule_test.go index 2d6e120cf95..f36c1de6a86 100644 --- a/translator/translate/otel/pipeline/opentelemetry/merge_rule_test.go +++ b/translator/translate/otel/pipeline/opentelemetry/merge_rule_test.go @@ -75,3 +75,62 @@ func TestMergeRule_DatabaseInsights(t *testing.T) { assert.Contains(t, dbi, "postgresql", "postgresql should be preserved after merge") assert.Contains(t, dbi, "mysql", "mysql should be preserved after merge") } + +func TestMergeRule_DatabaseInsights_AllThreeEngines(t *testing.T) { + // Verify that postgresql, mysql, and sqlserver from separate configs merge correctly + // under database_insights (simulates separate SSM parameters) + source1 := map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "postgresql": []interface{}{ + map[string]interface{}{ + "endpoint": "localhost:5432", + "instance_name": "pg-test", + }, + }, + }, + }, + }, + } + source2 := map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "mysql": []interface{}{ + map[string]interface{}{ + "endpoint": "localhost:3306", + "instance_name": "mysql-test", + }, + }, + }, + }, + }, + } + source3 := map[string]interface{}{ + "opentelemetry": map[string]interface{}{ + "collect": map[string]interface{}{ + "database_insights": map[string]interface{}{ + "sqlserver": []interface{}{ + map[string]interface{}{ + "endpoint": "localhost:1433", + "instance_name": "sqlserver-test", + }, + }, + }, + }, + }, + } + + // Merge source1 into source2, then source3 into source2 (source2 acts as result) + mergeJsonUtil.MergeRuleMap["opentelemetry"].Merge(source1, source2) + mergeJsonUtil.MergeRuleMap["opentelemetry"].Merge(source3, source2) + + otel := source2["opentelemetry"].(map[string]interface{}) + collect := otel["collect"].(map[string]interface{}) + dbi := collect["database_insights"].(map[string]interface{}) + + assert.Contains(t, dbi, "postgresql", "postgresql should be preserved after merge") + assert.Contains(t, dbi, "mysql", "mysql should be preserved after merge") + assert.Contains(t, dbi, "sqlserver", "sqlserver should be preserved after merge") +} From cc2cbeb4e7571381f4869b619cea8b3238a88c22 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Wed, 29 Jul 2026 18:17:26 +0000 Subject: [PATCH 07/12] feat(dbi): add SQL Server application.name attribute support Add support for tracking SQL Server sessions by application name, matching PostgreSQL's existing application.name dimension for DBI workload analysis. Changes: - Add sqlserver.active_sessions.by_app connector metric with sqlserver.application.name attribute dimension - Add replace_match transform for sqlserver.application.name to set 'unknown' default for NULL values - Update tests to expect 8 connector metrics (was 7) and 6 transform statements (was 5) - Ensure 13 Windows-only Performance Monitor metrics are correctly disabled on Linux (lock.wait_time.avg, page metrics, transaction metrics, and transaction_log metrics) - Add SQLServerKey constant and DatabaseInsightsSqlServerKey to common package - Integrate SQL Server receiver creation in databaseinsights translator - Update go.mod to point to committed sqlserverreceiver with application.name support (v0.0.0-20260729175257-2c50db1bb14e) - Regenerate all sample YAML configs with new metrics and transforms The application.name attribute enables DBAs to: - Identify which applications are generating database load - Track performance and resource consumption per application - Correlate application behavior with database metrics Testing: - All unit tests passing for connectors, processors, receivers - All pipeline integration tests passing - Linux config verified with Windows-only metrics disabled - Windows config verified with all 13 Performance Monitor metrics enabled --- go.mod | 2 +- go.sum | 2 + .../combined_v1_v2_ec2_config.yaml | 175 +- .../combined_v1_v2_eks_config.yaml | 171 +- .../dbi_sqlserver_config_linux.yaml | 163 +- .../dbi_sqlserver_config_windows.conf | 15 + .../dbi_sqlserver_config_windows.json | 22 + .../dbi_sqlserver_config_windows.yaml | 1407 +++++++++++++++++ .../tocwconfig/tocwconfig_windows_test.go | 6 + .../connector/count/dbi_dbload_sqlserver.yaml | 8 + .../otel/connector/count/translator_test.go | 4 +- .../databaseinsights/translator.go | 9 +- ...ransform_dbi_fix_start_time_sqlserver.yaml | 1 + .../transformprocessor/translator_test.go | 3 +- .../otel/receiver/sqlserver/translator.go | 79 +- .../receiver/sqlserver/translator_test.go | 89 +- 16 files changed, 1902 insertions(+), 254 deletions(-) create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.conf create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.json create mode 100644 translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.yaml diff --git a/go.mod b/go.mod index ff59cebfbdf..8ad1c26e903 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ replace ( github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260723202011-09a6da50bc48 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/postgresqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver => /home/larkirs/workplace/opentelemetry-collector-contrib/receiver/sqlserverreceiver + github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sqlserverreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/sqlserverreceiver v0.0.0-20260729175257-2c50db1bb14e // Cherry-pick of upstream Query XML support for windowseventlogreceiver https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/39055 github.com/open-telemetry/opentelemetry-collector-contrib/receiver/windowseventlogreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/windowseventlogreceiver v0.0.0-20260717191209-ee093fbfffbd ) diff --git a/go.sum b/go.sum index 088cc685a61..0b50a2e41ce 100644 --- a/go.sum +++ b/go.sum @@ -284,6 +284,8 @@ github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgres github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:DdKZOg4y/ac/f/ENvYWWg6e6r+INsAkx6DqRXzps1TU= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd h1:gguRr06gAfXYB1kxUZH7VaZobUauXRX+uNWGA0hsGx4= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:pa2WwKwnYyS/Wviu8P/uCm7JmtrxtB+IG1f8+b+VJF0= +github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/sqlserverreceiver v0.0.0-20260729175257-2c50db1bb14e h1:pJMbMtc5bu9RBkxwNiURYnvwgwVmaVkGbFwe3sa2XcE= +github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/sqlserverreceiver v0.0.0-20260729175257-2c50db1bb14e/go.mod h1:OtLoAVrHDh9R5pJoX8QJeQo1MyaNFTRz0bqH9sNfhVY= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/windowseventlogreceiver v0.0.0-20260717191209-ee093fbfffbd h1:VWN/rHtEICFrkNEdzv4Z0Z2Tu5gSw7HWnu+WfdRmQz0= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/windowseventlogreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:hfCxzEKq6utMJEq/mqehk55jpp7zCoiNs1yDp7WZ+dY= github.com/amir/raidman v0.0.0-20170415203553-1ccc43bfb9c9 h1:FXrPTd8Rdlc94dKccl7KPmdmIbVh/OjelJ8/vgMRzcQ= diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml index cdeb30dd5a0..88a18318503 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_ec2_config.yaml @@ -152,6 +152,14 @@ connectors: metric.datapoint.count: description: The number of data points observed. logs: + sqlserver.active_sessions.by_app: + attributes: + - key: db.system.name + - key: sqlserver.application.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by application sqlserver.active_sessions.by_db: attributes: - key: db.system.name @@ -680,6 +688,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.execution_count"] != nil description: Number of executions @@ -697,6 +707,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_elapsed_time"] != nil description: Total elapsed time (seconds) @@ -714,6 +726,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_worker_time"] != nil description: Total CPU (worker) time (seconds) @@ -731,6 +745,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_reads"] != nil description: Total logical reads (pages) @@ -748,6 +764,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_writes"] != nil description: Total logical writes (pages) @@ -765,6 +783,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_physical_reads"] != nil description: Total physical reads (pages) @@ -782,6 +802,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_rows"] != nil description: Total rows returned @@ -799,6 +821,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_grant_kb"] != nil description: Total memory grant (KB) @@ -1483,6 +1507,7 @@ processors: - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown") trace_statements: [] transform/dbi_logs_mysql_raw-events_0: error_mode: ignore @@ -2857,9 +2882,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -2867,7 +2892,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -2875,7 +2908,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -2883,38 +2916,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -2922,13 +2955,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -2940,9 +2973,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -2959,6 +2992,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -2966,27 +3001,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -3013,7 +3048,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor sqlserver/metrics_0: @@ -3046,9 +3084,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -3056,7 +3094,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -3064,7 +3110,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -3072,38 +3118,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -3111,13 +3157,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -3129,9 +3175,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -3148,6 +3194,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -3155,27 +3203,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -3202,7 +3250,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor telegraf_cpu: @@ -3440,13 +3491,13 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_swap - - telegraf_processes - - telegraf_netstat - - telegraf_cpu - telegraf_mem + - telegraf_netstat - telegraf_disk + - telegraf_swap + - telegraf_processes - telegraf_procstat/1917393364 + - telegraf_cpu metrics/host_metrics: exporters: - forward/opentelemetry @@ -3461,8 +3512,8 @@ service: - ec2tagger - awsentity/service/telegraf receivers: - - telegraf_statsd - telegraf_socket_listener + - telegraf_statsd metrics/hostDeltaMetrics: exporters: - awscloudwatch @@ -3471,8 +3522,8 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_net - telegraf_diskio + - telegraf_net metrics/opentelemetry: exporters: - otlphttp/metrics diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml index e93223067be..ad2494f9813 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml +++ b/translator/tocwconfig/sampleConfig/opentelemetry/combined_v1_v2_eks_config.yaml @@ -152,6 +152,14 @@ connectors: metric.datapoint.count: description: The number of data points observed. logs: + sqlserver.active_sessions.by_app: + attributes: + - key: db.system.name + - key: sqlserver.application.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by application sqlserver.active_sessions.by_db: attributes: - key: db.system.name @@ -680,6 +688,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.execution_count"] != nil description: Number of executions @@ -697,6 +707,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_elapsed_time"] != nil description: Total elapsed time (seconds) @@ -714,6 +726,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_worker_time"] != nil description: Total CPU (worker) time (seconds) @@ -731,6 +745,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_reads"] != nil description: Total logical reads (pages) @@ -748,6 +764,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_writes"] != nil description: Total logical writes (pages) @@ -765,6 +783,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_physical_reads"] != nil description: Total physical reads (pages) @@ -782,6 +802,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_rows"] != nil description: Total rows returned @@ -799,6 +821,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_grant_kb"] != nil description: Total memory grant (KB) @@ -1916,6 +1940,7 @@ processors: - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown") trace_statements: [] transform/dbi_logs_mysql_raw-events_0: error_mode: ignore @@ -3543,9 +3568,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -3553,7 +3578,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -3561,7 +3594,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -3569,38 +3602,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -3608,13 +3641,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -3626,9 +3659,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -3645,6 +3678,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -3652,27 +3687,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -3699,7 +3734,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor sqlserver/metrics_0: @@ -3732,9 +3770,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -3742,7 +3780,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -3750,7 +3796,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -3758,38 +3804,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -3797,13 +3843,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -3815,9 +3861,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -3834,6 +3880,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -3841,27 +3889,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -3888,7 +3936,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor telegraf_cpu: @@ -4296,13 +4347,13 @@ service: - ec2tagger - awsentity/resource receivers: - - telegraf_processes - - telegraf_netstat - - telegraf_cpu - telegraf_swap - - telegraf_disk - telegraf_procstat/1917393364 + - telegraf_cpu - telegraf_mem + - telegraf_processes + - telegraf_netstat + - telegraf_disk metrics/host_metrics: exporters: - forward/opentelemetry diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml index 220cc8d231b..0b5b702d4ec 100644 --- a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_linux.yaml @@ -4,6 +4,14 @@ connectors: metric.datapoint.count: description: The number of data points observed. logs: + sqlserver.active_sessions.by_app: + attributes: + - key: db.system.name + - key: sqlserver.application.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by application sqlserver.active_sessions.by_db: attributes: - key: db.system.name @@ -78,6 +86,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.execution_count"] != nil description: Number of executions @@ -95,6 +105,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_elapsed_time"] != nil description: Total elapsed time (seconds) @@ -112,6 +124,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_worker_time"] != nil description: Total CPU (worker) time (seconds) @@ -129,6 +143,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_reads"] != nil description: Total logical reads (pages) @@ -146,6 +162,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_logical_writes"] != nil description: Total logical writes (pages) @@ -163,6 +181,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_physical_reads"] != nil description: Total physical reads (pages) @@ -180,6 +200,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_rows"] != nil description: Total rows returned @@ -197,6 +219,8 @@ connectors: optional: false - key: sqlserver.query_plan_hash optional: false + - key: db.namespace + optional: false conditions: - attributes["sqlserver.total_grant_kb"] != nil description: Total memory grant (KB) @@ -638,6 +662,7 @@ processors: - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown") trace_statements: [] transform/dbi_logs_sqlserver_raw-events_0: error_mode: ignore @@ -880,9 +905,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -890,7 +915,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -898,7 +931,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -906,38 +939,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -945,13 +978,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -963,9 +996,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -982,6 +1015,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -989,27 +1024,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -1036,7 +1071,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor sqlserver/metrics_0: @@ -1069,9 +1107,9 @@ receivers: - database.status enabled: false sqlserver.database.execution.errors: - enabled: false + enabled: true sqlserver.database.full_scan.rate: - enabled: false + enabled: true sqlserver.database.io: aggregation_strategy: sum attributes: @@ -1079,7 +1117,15 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true sqlserver.database.latency: aggregation_strategy: sum attributes: @@ -1087,7 +1133,7 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.operations: aggregation_strategy: sum attributes: @@ -1095,38 +1141,38 @@ receivers: - logical_filename - file_type - direction - enabled: false + enabled: true sqlserver.database.tempdb.space: aggregation_strategy: sum attributes: - tempdb.state - enabled: false + enabled: true sqlserver.database.tempdb.version_store.size: - enabled: false + enabled: true sqlserver.deadlock.rate: enabled: true sqlserver.forwarded_records.rate: enabled: true sqlserver.index.search.rate: - enabled: false + enabled: true sqlserver.latch.wait.rate: enabled: true sqlserver.lock.timeout.rate: - enabled: false + enabled: true sqlserver.lock.wait.count: - enabled: false + enabled: true sqlserver.lock.wait.rate: enabled: true sqlserver.lock.wait_time.avg: - enabled: true - sqlserver.login.rate: enabled: false + sqlserver.login.rate: + enabled: true sqlserver.logout.rate: - enabled: false + enabled: true sqlserver.memory.grants.pending.count: enabled: true sqlserver.memory.usage: - enabled: false + enabled: true sqlserver.os.wait.duration: aggregation_strategy: sum attributes: @@ -1134,13 +1180,13 @@ receivers: - wait.type enabled: false sqlserver.page.buffer_cache.free_list.stalls.rate: - enabled: false + enabled: true sqlserver.page.buffer_cache.hit_ratio: enabled: true sqlserver.page.checkpoint.flush.rate: - enabled: true + enabled: false sqlserver.page.lazy_write.rate: - enabled: true + enabled: false sqlserver.page.life_expectancy: aggregation_strategy: avg attributes: @@ -1152,9 +1198,9 @@ receivers: aggregation_strategy: avg attributes: - type - enabled: true + enabled: false sqlserver.page.split.rate: - enabled: true + enabled: false sqlserver.processes.blocked: enabled: true sqlserver.replica.data.rate: @@ -1171,6 +1217,8 @@ receivers: enabled: false sqlserver.resource_pool.disk.throttled.write.rate: enabled: false + sqlserver.session.count: + enabled: true sqlserver.table.count: aggregation_strategy: sum attributes: @@ -1178,27 +1226,27 @@ receivers: - table.status enabled: false sqlserver.transaction.active.count: - enabled: true + enabled: false sqlserver.transaction.delay: enabled: false sqlserver.transaction.mirror_write.rate: enabled: false sqlserver.transaction.rate: - enabled: true + enabled: false sqlserver.transaction.write.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.data.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.rate: - enabled: true + enabled: false sqlserver.transaction_log.flush.wait.rate: - enabled: true + enabled: false sqlserver.transaction_log.growth.count: - enabled: true + enabled: false sqlserver.transaction_log.shrink.count: - enabled: true + enabled: false sqlserver.transaction_log.usage: - enabled: true + enabled: false sqlserver.user.connection.count: enabled: true passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials @@ -1225,7 +1273,10 @@ receivers: top_query_collection: collection_interval: 1m0s lookback_time: 0s + max_query_plan_size: 921600 max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s top_query_count: 200 username: cw_monitor service: diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.conf b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.conf new file mode 100644 index 00000000000..39a90aaae9c --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.conf @@ -0,0 +1,15 @@ +[agent] + collection_jitter = "0s" + debug = false + flush_interval = "1s" + flush_jitter = "0s" + hostname = "" + interval = "60s" + logfile = "C:\\ProgramData\\Amazon\\AmazonCloudWatchAgent\\Logs\\amazon-cloudwatch-agent.log" + logtarget = "lumberjack" + metric_batch_size = 1000 + metric_buffer_limit = 10000 + omit_hostname = false + precision = "" + quiet = false + round_interval = false diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.json b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.json new file mode 100644 index 00000000000..9e7802a53f3 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.json @@ -0,0 +1,22 @@ +{ + "agent": { + "region": "us-west-2" + }, + "opentelemetry": { + "collect": { + "database_insights": { + "sqlserver": [ + { + "endpoint": "localhost:1433", + "instance_name": "pentest-sqlserver", + "username": "cw_monitor", + "password_file": "sampleConfig/opentelemetry/testdata/.sqlserver_credentials", + "logs": { + "file_path": "C:\\Program Files\\Microsoft SQL Server\\MSSQL16.MSSQLSERVER\\MSSQL\\Log\\ERRORLOG" + } + } + ] + } + } + } +} diff --git a/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.yaml b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.yaml new file mode 100644 index 00000000000..e1bad9291c7 --- /dev/null +++ b/translator/tocwconfig/sampleConfig/opentelemetry/dbi_sqlserver_config_windows.yaml @@ -0,0 +1,1407 @@ +connectors: + count/dbi_dbload_sqlserver: + datapoints: + metric.datapoint.count: + description: The number of data points observed. + logs: + sqlserver.active_sessions.by_app: + attributes: + - key: db.system.name + - key: sqlserver.application.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by application + sqlserver.active_sessions.by_db: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by database + sqlserver.active_sessions.by_host: + attributes: + - key: db.system.name + - key: network.peer.address + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by host + sqlserver.active_sessions.by_sql: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query hash + sqlserver.active_sessions.by_sql_wait: + attributes: + - key: db.system.name + - key: sqlserver.query_hash + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by query and wait category + sqlserver.active_sessions.by_user: + attributes: + - key: db.system.name + - key: user.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by user + sqlserver.active_sessions.by_wait: + attributes: + - key: db.system.name + - key: sqlserver.wait_category + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Active sessions by wait category + sqlserver.active_sessions.count: + attributes: + - key: db.system.name + - key: db.namespace + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + description: Total active sessions + metrics: + metric.count: + description: The number of metrics observed. + spanevents: + trace.span.event.count: + description: The number of span events observed. + spans: + trace.span.count: + description: The number of spans observed. + forward/opentelemetry: {} + signaltometrics/dbi_topsql_sqlserver: + logs: + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.execution_count"] != nil + description: Number of executions + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.execution_count + sum: + value: Int(attributes["sqlserver.execution_count"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_elapsed_time"] != nil + description: Total elapsed time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_elapsed_time + sum: + value: Double(attributes["sqlserver.total_elapsed_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_worker_time"] != nil + description: Total CPU (worker) time (seconds) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_worker_time + sum: + value: Double(attributes["sqlserver.total_worker_time"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_logical_reads"] != nil + description: Total logical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_reads + sum: + value: Int(attributes["sqlserver.total_logical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_logical_writes"] != nil + description: Total logical writes (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_logical_writes + sum: + value: Int(attributes["sqlserver.total_logical_writes"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_physical_reads"] != nil + description: Total physical reads (pages) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_physical_reads + sum: + value: Int(attributes["sqlserver.total_physical_reads"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_rows"] != nil + description: Total rows returned + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_rows + sum: + value: Int(attributes["sqlserver.total_rows"]) + unit: "" + - attributes: + - key: db.system.name + optional: false + - key: sqlserver.query_hash + optional: false + - key: sqlserver.query_plan_hash + optional: false + - key: db.namespace + optional: false + conditions: + - attributes["sqlserver.total_grant_kb"] != nil + description: Total memory grant (KB) + include_resource_attributes: + - key: service.instance.id + optional: false + name: sqlserver.total_grant_kb + sum: + value: Int(attributes["sqlserver.total_grant_kb"]) + unit: "" +exporters: + awscloudwatch/systemmetrics: + backoff_retry_base: 1m0s + downgrade_errors: true + force_flush_interval: 1m0s + max_concurrent_publishers: 1 + max_datums_per_call: 1000 + max_retry_count: 2 + max_values_per_datum: 150 + middleware: agenthealth/metrics + namespace: CWAgent/System + region: us-west-2 + resource_to_telemetry_conversion: + enabled: true + rollup_dimensions: + - [] + otlphttp/logs: + auth: + authenticator: agenthealth/opentelemetry_logs + compression: gzip + encoding: proto + idle_conn_timeout: 1m30s + logs_endpoint: https://logs.us-west-2.amazonaws.com/v1/logs + max_idle_conns: 100 + metrics_endpoint: "" + retry_on_failure: + enabled: true + initial_interval: 5s + max_elapsed_time: 5m0s + max_interval: 30s + multiplier: 1.5 + randomization_factor: 0.5 + sending_queue: + block_on_overflow: false + blocking: false + enabled: true + num_consumers: 10 + queue_size: 1000 + sizer: {} + wait_for_result: false + timeout: 30s + traces_endpoint: "" + write_buffer_size: 524288 + otlphttp/metrics: + auth: + authenticator: agenthealth/opentelemetry_metrics + compression: gzip + encoding: proto + idle_conn_timeout: 1m30s + logs_endpoint: "" + max_idle_conns: 100 + metrics_endpoint: https://monitoring.us-west-2.amazonaws.com/v1/metrics + retry_on_failure: + enabled: true + initial_interval: 5s + max_elapsed_time: 5m0s + max_interval: 30s + multiplier: 1.5 + randomization_factor: 0.5 + sending_queue: + block_on_overflow: false + blocking: false + enabled: true + num_consumers: 10 + queue_size: 1000 + sizer: {} + wait_for_result: false + timeout: 30s + traces_endpoint: "" + write_buffer_size: 524288 +extensions: + agenthealth/metrics: + is_usage_data_enabled: true + stats: + operations: + - PutMetricData + usage_flags: + mode: "" + region_type: ACJ + agenthealth/opentelemetry_logs: + additional_auth: headers_setter/logs + is_usage_data_enabled: true + stats: + operations: + - '*' + usage_flags: + mode: "" + region_type: ACJ + agenthealth/opentelemetry_metrics: + additional_auth: sigv4auth/monitoring + is_usage_data_enabled: true + stats: + operations: + - '*' + usage_flags: + mode: "" + region_type: ACJ + awscloudwatchlogsprovisioner: + additional_auth: sigv4auth/logs + imds_retries: 1 + logs_provision_failure_backoff: 5s + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 10 + headers_setter/logs: + additional_auth: awscloudwatchlogsprovisioner + headers: + - action: upsert + from_context: aws.log.group.name + key: x-aws-log-group + - action: upsert + from_context: aws.log.stream.name + key: x-aws-log-stream + sigv4auth/logs: + assume_role: {} + imds_retries: 1 + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 30 + service: logs + sigv4auth/monitoring: + assume_role: {} + imds_retries: 1 + max_retries: 2 + num_workers: 8 + region: us-west-2 + request_timeout_seconds: 30 + service: monitoring +processors: + attributestocontext/opentelemetry: + actions: + - from_resource_attribute: aws.log.group.name + key: aws.log.group.name + - from_resource_attribute: aws.log.stream.name + key: aws.log.stream.name + batch/opentelemetry_logs: + metadata_cardinality_limit: 1000 + metadata_keys: + - aws.log.group.name + - aws.log.stream.name + send_batch_max_size: 10000 + send_batch_size: 10000 + timeout: 30s + batch/opentelemetry_metrics: + metadata_cardinality_limit: 1000 + send_batch_max_size: 1000 + send_batch_size: 1000 + timeout: 30s + batch/systemmetrics: + metadata_cardinality_limit: 1000 + send_batch_max_size: 0 + send_batch_size: 8192 + timeout: 15m0s + filter/dbi_exclude_monitor_sqlserver_0: + error_mode: propagate + logs: + log_record: + - attributes["user.name"] == "cw_monitor" + metrics: {} + spans: {} + traces: {} + groupbyattrs/files: + keys: + - log.file.name + resourcedetection/opentelemetry: + aks: + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + k8s.cluster.name: + enabled: false + azure: + resource_attributes: + azure.resourcegroup.name: + enabled: true + azure.vm.name: + enabled: true + azure.vm.scaleset.name: + enabled: true + azure.vm.size: + enabled: true + cloud.account.id: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + tags: [] + consul: + address: "" + datacenter: "" + namespace: "" + resource_attributes: + cloud.region: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + token_file: "" + detectors: + - eks + - env + - ec2 + docker: + resource_attributes: + host.name: + enabled: true + os.type: + enabled: true + ec2: + fail_on_missing_metadata: false + max_attempts: 3 + max_backoff: 20s + resource_attributes: + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + host.id: + enabled: true + host.image.id: + enabled: true + host.name: + enabled: true + host.type: + enabled: true + tags: + - ^kubernetes.io/cluster/.*$ + - ^aws:autoscaling:groupName + ecs: + resource_attributes: + aws.ecs.cluster.arn: + enabled: true + aws.ecs.launchtype: + enabled: true + aws.ecs.task.arn: + enabled: true + aws.ecs.task.family: + enabled: true + aws.ecs.task.id: + enabled: true + aws.ecs.task.revision: + enabled: true + aws.log.group.arns: + enabled: true + aws.log.group.names: + enabled: true + aws.log.stream.arns: + enabled: true + aws.log.stream.names: + enabled: true + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + eks: + resource_attributes: + cloud.account.id: + enabled: false + cloud.platform: + enabled: true + cloud.provider: + enabled: true + k8s.cluster.name: + enabled: false + elasticbeanstalk: + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + deployment.environment: + enabled: true + service.instance.id: + enabled: true + service.version: + enabled: true + gcp: + resource_attributes: + cloud.account.id: + enabled: true + cloud.availability_zone: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + faas.id: + enabled: true + faas.instance: + enabled: true + faas.name: + enabled: true + faas.version: + enabled: true + gcp.cloud_run.job.execution: + enabled: true + gcp.cloud_run.job.task_index: + enabled: true + gcp.gce.instance.hostname: + enabled: false + gcp.gce.instance.name: + enabled: false + gcp.gce.instance_group_manager.name: + enabled: true + gcp.gce.instance_group_manager.region: + enabled: true + gcp.gce.instance_group_manager.zone: + enabled: true + host.id: + enabled: true + host.name: + enabled: true + host.type: + enabled: true + k8s.cluster.name: + enabled: true + heroku: + resource_attributes: + cloud.provider: + enabled: true + heroku.app.id: + enabled: true + heroku.dyno.id: + enabled: true + heroku.release.commit: + enabled: true + heroku.release.creation_timestamp: + enabled: true + service.instance.id: + enabled: true + service.name: + enabled: true + service.version: + enabled: true + idle_conn_timeout: 1m30s + k8snode: + auth_type: serviceAccount + context: "" + kube_config_path: "" + node_from_env_var: "" + resource_attributes: + k8s.node.name: + enabled: true + k8s.node.uid: + enabled: true + kubeadm: + auth_type: serviceAccount + context: "" + kube_config_path: "" + resource_attributes: + k8s.cluster.name: + enabled: true + k8s.cluster.uid: + enabled: true + lambda: + resource_attributes: + aws.log.group.names: + enabled: true + aws.log.stream.names: + enabled: true + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + faas.instance: + enabled: true + faas.max_memory: + enabled: true + faas.name: + enabled: true + faas.version: + enabled: true + max_idle_conns: 100 + openshift: + address: "" + resource_attributes: + cloud.platform: + enabled: true + cloud.provider: + enabled: true + cloud.region: + enabled: true + k8s.cluster.name: + enabled: true + tls: {} + token: "" + override: true + system: + resource_attributes: + host.arch: + enabled: false + host.cpu.cache.l2.size: + enabled: false + host.cpu.family: + enabled: false + host.cpu.model.id: + enabled: false + host.cpu.model.name: + enabled: false + host.cpu.stepping: + enabled: false + host.cpu.vendor.id: + enabled: false + host.id: + enabled: false + host.ip: + enabled: false + host.mac: + enabled: false + host.name: + enabled: true + os.description: + enabled: false + os.type: + enabled: true + os.version: + enabled: false + timeout: 2s + transform/dbi_fix_start_time_sqlserver: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: datapoint + error_mode: ignore + statements: + - set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0 + - replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU") + - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") + - replace_match(datapoint.attributes["user.name"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown") + trace_statements: [] + transform/dbi_logs_sqlserver_raw-events_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/raw-events") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "pentest-sqlserver"], "/")) + metric_statements: [] + trace_statements: [] + transform/dbi_logs_sqlserver_server-logs_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], "/aws/self-managed-database-insights/sqlserver/server-logs") + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], "pentest-sqlserver"], "/")) + - context: log + error_mode: ignore + statements: + - delete_key(attributes, "timestamp") + - delete_key(attributes, "severity") + metric_statements: [] + trace_statements: [] + transform/dbi_resource_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "pentest-sqlserver") + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["db.system.name"], "sqlserver") + - set(resource.attributes["db.instance.name"], "pentest-sqlserver") + trace_statements: [] + transform/dbi_scope_sqlserver_0: + error_mode: ignore + flatten_data: false + log_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-database-insights") + trace_statements: [] + transform/host_metrics_scope: + error_mode: ignore + flatten_data: false + log_statements: [] + metric_statements: + - context: scope + error_mode: ignore + statements: + - set(scope.attributes["cloudwatch.source"], "cloudwatch-agent") + - set(scope.attributes["cloudwatch.solution"], "otel-host-metrics") + trace_statements: [] + transform/identity: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + metric_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + trace_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["service.name"], "unknown_service") where resource.attributes["service.name"] == nil + - set(resource.attributes["cloud.resource_id"], Concat(["arn:aws:ec2", resource.attributes["cloud.region"], resource.attributes["cloud.account.id"], Concat(["instance", resource.attributes["host.id"]], "/")], ":")) where resource.attributes["cloud.resource_id"] == nil and resource.attributes["host.id"] != nil and resource.attributes["cloud.platform"] == "aws_ec2" + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], resource.attributes["ec2.tag.aws:autoscaling:groupName"]], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["ec2.tag.aws:autoscaling:groupName"] != nil + - set(resource.attributes["deployment.environment.name"], Concat([resource.attributes["cloud.platform"], "default"], ":")) where resource.attributes["deployment.environment.name"] == nil and resource.attributes["cloud.platform"] != nil + transform/logs_cleanup: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - delete_key(resource.attributes, "aws.log.group.name") + - delete_key(resource.attributes, "aws.log.stream.name") + - delete_key(resource.attributes, "aws.log.source") + metric_statements: [] + trace_statements: [] + transform/logs_routing: + error_mode: ignore + flatten_data: false + log_statements: + - context: resource + error_mode: ignore + statements: + - set(resource.attributes["aws.log.group.name"], Concat(["/aws/cwagent", resource.attributes["aws.log.source"]], "/")) where resource.attributes["aws.log.group.name"] == nil and resource.attributes["aws.log.source"] != nil + - set(resource.attributes["aws.log.group.name"], "/aws/cwagent/default") where resource.attributes["aws.log.group.name"] == nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["log.file.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["aws.log.source"] == "files" and resource.attributes["host.id"] != nil and resource.attributes["log.file.name"] != nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["log.file.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["aws.log.source"] == "files" and resource.attributes["host.name"] != nil and resource.attributes["log.file.name"] != nil + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["service.namespace"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil and resource.attributes["service.namespace"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.id"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["service.namespace"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil and resource.attributes["service.namespace"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], Concat([resource.attributes["host.name"], resource.attributes["service.name"]], "/")) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil and resource.attributes["service.name"] != nil and resource.attributes["service.name"] != "unknown_service" + - set(resource.attributes["aws.log.stream.name"], resource.attributes["host.id"]) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.id"] != nil + - set(resource.attributes["aws.log.stream.name"], resource.attributes["host.name"]) where resource.attributes["aws.log.stream.name"] == nil and resource.attributes["host.name"] != nil + - set(resource.attributes["aws.log.stream.name"], "default") where resource.attributes["aws.log.stream.name"] == nil + metric_statements: [] + trace_statements: [] +receivers: + filelog/sqlserver_0: + encoding: utf-8 + include: + - C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Log\ERRORLOG + multiline: + line_start_pattern: ^\d{4}-\d{2}-\d{2} + operators: + - regex: (?P\d{4}-\s{0,1}\d{1,2}-\s{0,1}\d{1,2} \d{2}:\d{2}:\d{2}\.(\d{1,9})) + timestamp: + layout: 2006-1-_2 15:04:05.999999999 + layout_type: gotime + location: UTC + parse_from: attributes.timestamp + type: regex_parser + - on_error: send_quiet + regex: 'Error: \d+, Severity: (?P\d+), State: \d+' + severity: + mapping: + error: + - max: 19 + min: 17 + fatal: + - max: 25 + min: 20 + info: + - max: 10 + min: 0 + warn: + - max: 16 + min: 11 + parse_from: attributes.severity + type: regex_parser + start_at: end + hostmetrics/opentelemetry: + collection_interval: 30s + initial_delay: 1s + scrapers: + cpu: + metrics: + system.cpu.logical.count: + enabled: true + system.cpu.physical.count: + enabled: true + system.cpu.utilization: + enabled: true + disk: null + filesystem: + metrics: + system.filesystem.utilization: + enabled: true + load: null + memory: + metrics: + system.memory.limit: + enabled: true + system.memory.page_size: + enabled: true + system.memory.utilization: + enabled: true + network: null + process: + include: + match_type: regexp + names: + - sqlservr.* + metrics: + process.cpu.utilization: + enabled: true + process.memory.utilization: + enabled: true + process.threads: + enabled: true + mute_process_all_errors: true + timeout: 0s + sqlserver/events_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: true + sqlserver.database.full_scan.rate: + enabled: true + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: true + sqlserver.database.tempdb.version_store.size: + enabled: true + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: true + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: true + sqlserver.lock.wait.count: + enabled: true + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: true + sqlserver.logout.rate: + enabled: true + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: true + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: true + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.session.count: + enabled: true + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: false + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_plan_size: 921600 + max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s + top_query_count: 200 + username: cw_monitor + sqlserver/metrics_0: + collection_interval: 10s + computer_name: "" + datasource: "" + events: + db.server.query_sample: + enabled: true + db.server.top_query: + enabled: true + initial_delay: 1s + instance_name: "" + metrics: + sqlserver.batch.request.rate: + enabled: true + sqlserver.batch.sql_compilation.rate: + enabled: true + sqlserver.batch.sql_recompilation.rate: + enabled: true + sqlserver.computer.uptime: + enabled: false + sqlserver.cpu.count: + enabled: false + sqlserver.database.backup_or_restore.rate: + enabled: false + sqlserver.database.count: + aggregation_strategy: avg + attributes: + - database.status + enabled: false + sqlserver.database.execution.errors: + enabled: true + sqlserver.database.full_scan.rate: + enabled: true + sqlserver.database.io: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.io.stall_queued: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.latency: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.operations: + aggregation_strategy: sum + attributes: + - physical_filename + - logical_filename + - file_type + - direction + enabled: true + sqlserver.database.tempdb.space: + aggregation_strategy: sum + attributes: + - tempdb.state + enabled: true + sqlserver.database.tempdb.version_store.size: + enabled: true + sqlserver.deadlock.rate: + enabled: true + sqlserver.forwarded_records.rate: + enabled: true + sqlserver.index.search.rate: + enabled: true + sqlserver.latch.wait.rate: + enabled: true + sqlserver.lock.timeout.rate: + enabled: true + sqlserver.lock.wait.count: + enabled: true + sqlserver.lock.wait.rate: + enabled: true + sqlserver.lock.wait_time.avg: + enabled: true + sqlserver.login.rate: + enabled: true + sqlserver.logout.rate: + enabled: true + sqlserver.memory.grants.pending.count: + enabled: true + sqlserver.memory.usage: + enabled: true + sqlserver.os.wait.duration: + aggregation_strategy: sum + attributes: + - wait.category + - wait.type + enabled: false + sqlserver.page.buffer_cache.free_list.stalls.rate: + enabled: true + sqlserver.page.buffer_cache.hit_ratio: + enabled: true + sqlserver.page.checkpoint.flush.rate: + enabled: true + sqlserver.page.lazy_write.rate: + enabled: true + sqlserver.page.life_expectancy: + aggregation_strategy: avg + attributes: + - performance_counter.object_name + enabled: true + sqlserver.page.lookup.rate: + enabled: true + sqlserver.page.operation.rate: + aggregation_strategy: avg + attributes: + - type + enabled: true + sqlserver.page.split.rate: + enabled: true + sqlserver.processes.blocked: + enabled: true + sqlserver.replica.data.rate: + aggregation_strategy: avg + attributes: + - replica.direction + enabled: false + sqlserver.resource_pool.disk.operations: + aggregation_strategy: avg + attributes: + - direction + enabled: false + sqlserver.resource_pool.disk.throttled.read.rate: + enabled: false + sqlserver.resource_pool.disk.throttled.write.rate: + enabled: false + sqlserver.session.count: + enabled: true + sqlserver.table.count: + aggregation_strategy: sum + attributes: + - table.state + - table.status + enabled: false + sqlserver.transaction.active.count: + enabled: false + sqlserver.transaction.delay: + enabled: false + sqlserver.transaction.mirror_write.rate: + enabled: false + sqlserver.transaction.rate: + enabled: true + sqlserver.transaction.write.rate: + enabled: true + sqlserver.transaction_log.flush.data.rate: + enabled: true + sqlserver.transaction_log.flush.rate: + enabled: true + sqlserver.transaction_log.flush.wait.rate: + enabled: true + sqlserver.transaction_log.growth.count: + enabled: true + sqlserver.transaction_log.shrink.count: + enabled: true + sqlserver.transaction_log.usage: + enabled: true + sqlserver.user.connection.count: + enabled: true + passfile: sampleConfig/opentelemetry/testdata/.sqlserver_credentials + port: 1433 + query_sample_collection: + max_rows_per_query: 500 + resource_attributes: + host.name: + enabled: true + server.address: + enabled: false + server.port: + enabled: false + service.instance.id: + enabled: true + sqlserver.computer.name: + enabled: false + sqlserver.database.name: + enabled: true + sqlserver.instance.name: + enabled: false + server: localhost + timeout: 0s + top_query_collection: + collection_interval: 1m0s + lookback_time: 0s + max_query_plan_size: 921600 + max_query_sample_count: 5000 + query_plan_cache_size: 1000 + query_plan_cache_ttl: 1h0m0s + top_query_count: 200 + username: cw_monitor + systemmetrics: + collection_interval: 1m0s + initial_delay: 1s + timeout: 0s +service: + extensions: + - agenthealth/metrics + - sigv4auth/monitoring + - agenthealth/opentelemetry_metrics + - sigv4auth/logs + - awscloudwatchlogsprovisioner + - headers_setter/logs + - agenthealth/opentelemetry_logs + pipelines: + logs/dbi_sqlserver_0: + exporters: + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + receivers: + - sqlserver/metrics_0 + logs/dbi_sqlserver_rawevents_0: + exporters: + - forward/opentelemetry + processors: + - filter/dbi_exclude_monitor_sqlserver_0 + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_raw-events_0 + receivers: + - sqlserver/events_0 + logs/dbi_sqlserver_serverlogs_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - resourcedetection/opentelemetry + - groupbyattrs/files + - transform/dbi_resource_sqlserver_0 + - transform/dbi_logs_sqlserver_server-logs_0 + receivers: + - filelog/sqlserver_0 + logs/opentelemetry: + exporters: + - otlphttp/logs + processors: + - resourcedetection/opentelemetry + - transform/identity + - transform/logs_routing + - attributestocontext/opentelemetry + - transform/logs_cleanup + - batch/opentelemetry_logs + receivers: + - forward/opentelemetry + metrics/dbi_sqlserver_0: + exporters: + - forward/opentelemetry + processors: + - transform/dbi_scope_sqlserver_0 + - transform/dbi_resource_sqlserver_0 + - transform/dbi_fix_start_time_sqlserver + receivers: + - sqlserver/metrics_0 + - count/dbi_dbload_sqlserver + - signaltometrics/dbi_topsql_sqlserver + metrics/host_metrics: + exporters: + - forward/opentelemetry + processors: + - transform/host_metrics_scope + receivers: + - hostmetrics/opentelemetry + metrics/opentelemetry: + exporters: + - otlphttp/metrics + processors: + - resourcedetection/opentelemetry + - transform/identity + - batch/opentelemetry_metrics + receivers: + - forward/opentelemetry + metrics/systemmetrics: + exporters: + - awscloudwatch/systemmetrics + processors: + - batch/systemmetrics + receivers: + - systemmetrics + telemetry: + logs: + encoding: console + level: info + output_paths: + - C:\ProgramData\Amazon\AmazonCloudWatchAgent\Logs\amazon-cloudwatch-agent.log + sampling: + enabled: true + initial: 2 + thereafter: 500 + tick: 10s + metrics: + level: None + traces: + level: None diff --git a/translator/tocwconfig/tocwconfig_windows_test.go b/translator/tocwconfig/tocwconfig_windows_test.go index 95d0f114e7f..6cf7e90b9d3 100644 --- a/translator/tocwconfig/tocwconfig_windows_test.go +++ b/translator/tocwconfig/tocwconfig_windows_test.go @@ -54,3 +54,9 @@ func TestDefaultOtelConfigWindowsTranslation(t *testing.T) { verifyToTomlTranslation(t, input, "./sampleConfig/opentelemetry/default_otel_config_windows.conf") verifyToYamlTranslation(t, input, "./sampleConfig/opentelemetry/default_otel_config_windows.yaml") } + +func TestDBISqlServerConfigWindows(t *testing.T) { + resetContext(t) + context.CurrentContext().SetMode(config.ModeEC2) + checkTranslation(t, "opentelemetry/dbi_sqlserver_config_windows", "windows", nil, "") +} diff --git a/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml b/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml index 91a69efe50f..06965bdfef3 100644 --- a/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml +++ b/translator/translate/otel/connector/count/dbi_dbload_sqlserver.yaml @@ -1,4 +1,12 @@ logs: + sqlserver.active_sessions.by_app: + description: "Active sessions by application" + conditions: + - attributes["sqlserver.session_status"] != "sleeping" + attributes: + - key: db.system.name + - key: sqlserver.application.name + - key: db.namespace sqlserver.active_sessions.by_wait: description: "Active sessions by wait category" conditions: diff --git a/translator/translate/otel/connector/count/translator_test.go b/translator/translate/otel/connector/count/translator_test.go index e2952d9949a..5fcb96fcc10 100644 --- a/translator/translate/otel/connector/count/translator_test.go +++ b/translator/translate/otel/connector/count/translator_test.go @@ -61,7 +61,6 @@ func TestTranslateDbloadMysql(t *testing.T) { assert.Contains(t, countCfg.Logs, "mysql.active_sessions.by_host") assert.Contains(t, countCfg.Logs, "mysql.active_sessions.count") } - func TestTranslatorID_SqlServer(t *testing.T) { tr := NewTranslator(common.DbiConnectorDbload+"_"+common.SQLServerKey, common.SQLServerKey) assert.Equal(t, "count/dbi_dbload_sqlserver", tr.ID().String()) @@ -72,7 +71,8 @@ func TestTranslateDbloadSqlServer(t *testing.T) { cfg, err := tr.Translate(nil) require.NoError(t, err) countCfg := cfg.(*countconnector.Config) - assert.Len(t, countCfg.Logs, 7) + assert.Len(t, countCfg.Logs, 8) + assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_app") assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_wait") assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_user") assert.Contains(t, countCfg.Logs, "sqlserver.active_sessions.by_db") diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go index 83dcc236f8c..e6156c05a79 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go @@ -328,15 +328,10 @@ func (t *dbiTranslator) receiver(name string) common.ComponentTranslator { func (t *dbiTranslator) excludeMonitorFilter() common.ComponentTranslator { idx := strconv.Itoa(t.instanceIndex) - // SQL Server already filters out the monitoring session in the query itself + condition := fmt.Sprintf(`attributes["user.name"] == "%s"`, t.cfg.username) if t.cfg.engine == common.PostgreSQLKey { - condition := fmt.Sprintf(`attributes["user.name"] == "%s" or attributes["postgresql.rolname"] == "%s"`, t.cfg.username, t.cfg.username) - return filterprocessor.NewTranslatorWithLogCondition(common.DbiFilterExcludeMonitor+"_"+t.cfg.engine+"_"+idx, condition, common.OTTLErrorModePropagate) + condition = fmt.Sprintf(`attributes["user.name"] == "%s" or attributes["postgresql.rolname"] == "%s"`, t.cfg.username, t.cfg.username) } - - // For MySQL and SQL Server, use a filter that always passes (matches nothing) - // This allows all query samples through since the receivers already filter correctly - condition := `false` // Never matches, so nothing gets filtered return filterprocessor.NewTranslatorWithLogCondition(common.DbiFilterExcludeMonitor+"_"+t.cfg.engine+"_"+idx, condition, common.OTTLErrorModePropagate) } diff --git a/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml b/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml index 01c63552ab6..81d325f6cf2 100644 --- a/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml +++ b/translator/translate/otel/processor/transformprocessor/transform_dbi_fix_start_time_sqlserver.yaml @@ -8,3 +8,4 @@ metric_statements: - replace_match(datapoint.attributes["network.peer.address"], "", "unknown") - replace_match(datapoint.attributes["sqlserver.query_hash"], "", "unknown") - replace_match(datapoint.attributes["user.name"], "", "unknown") + - replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown") diff --git a/translator/translate/otel/processor/transformprocessor/translator_test.go b/translator/translate/otel/processor/transformprocessor/translator_test.go index 0a664c42e64..97ccb772197 100644 --- a/translator/translate/otel/processor/transformprocessor/translator_test.go +++ b/translator/translate/otel/processor/transformprocessor/translator_test.go @@ -117,10 +117,11 @@ func TestDbiFixStartTimeSqlServerTranslate(t *testing.T) { actualCfg := cfg.(*transformprocessor.Config) require.Len(t, actualCfg.MetricStatements, 1) assert.Equal(t, "datapoint", string(actualCfg.MetricStatements[0].Context)) - require.Len(t, actualCfg.MetricStatements[0].Statements, 5) + require.Len(t, actualCfg.MetricStatements[0].Statements, 6) assert.Equal(t, "set(datapoint.start_time_unix_nano, datapoint.time_unix_nano) where datapoint.start_time_unix_nano == 0", actualCfg.MetricStatements[0].Statements[0]) assert.Equal(t, `replace_match(datapoint.attributes["sqlserver.wait_category"], "", "CPU")`, actualCfg.MetricStatements[0].Statements[1]) assert.Equal(t, `replace_match(datapoint.attributes["user.name"], "", "unknown")`, actualCfg.MetricStatements[0].Statements[4]) + assert.Equal(t, `replace_match(datapoint.attributes["sqlserver.application.name"], "", "unknown")`, actualCfg.MetricStatements[0].Statements[5]) } func TestDbiResourceTranslate(t *testing.T) { diff --git a/translator/translate/otel/receiver/sqlserver/translator.go b/translator/translate/otel/receiver/sqlserver/translator.go index f4f70bb6260..67c119611fe 100644 --- a/translator/translate/otel/receiver/sqlserver/translator.go +++ b/translator/translate/otel/receiver/sqlserver/translator.go @@ -13,6 +13,8 @@ import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/receiver" + translatorconfig "github.com/aws/amazon-cloudwatch-agent/translator/config" + translatorcontext "github.com/aws/amazon-cloudwatch-agent/translator/context" "github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/common" ) @@ -75,47 +77,58 @@ func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { // Enable metrics disabled-by-default in the receiver but required by DBI. // These metrics align with RDS SQL Server monitoring best practices. - // Performance & Resource Metrics (RDS equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverProcessesBlocked.Enabled = true // RDS: BlockedTransactions - cfg.MetricsBuilderConfig.Metrics.SqlserverDeadlockRate.Enabled = true // RDS: Deadlocks/sec - cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryGrantsPendingCount.Enabled = true // RDS: Memory Grants Pending - cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryUsage.Enabled = true // RDS: FreeableMemory (inverse) + // Performance & Resource Metrics + cfg.MetricsBuilderConfig.Metrics.SqlserverProcessesBlocked.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDeadlockRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryGrantsPendingCount.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverMemoryUsage.Enabled = true - // Page & Buffer Pool Metrics (RDS equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverPageLookupRate.Enabled = true // RDS: Page Lookups/sec - cfg.MetricsBuilderConfig.Metrics.SqlserverForwardedRecordsRate.Enabled = true // Performance tuning metric - cfg.MetricsBuilderConfig.Metrics.SqlserverPageBufferCacheFreeListStallsRate.Enabled = true // Memory pressure indicator + // Page & Buffer Pool Metrics + cfg.MetricsBuilderConfig.Metrics.SqlserverPageLookupRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverForwardedRecordsRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverPageBufferCacheFreeListStallsRate.Enabled = true - // Wait Statistics (RDS Performance Insights equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverLatchWaitRate.Enabled = true // Concurrency metric - cfg.MetricsBuilderConfig.Metrics.SqlserverLockTimeoutRate.Enabled = true // Lock contention - cfg.MetricsBuilderConfig.Metrics.SqlserverLockWaitCount.Enabled = true // Lock contention + // Wait Statistics + cfg.MetricsBuilderConfig.Metrics.SqlserverLatchWaitRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverLockTimeoutRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverLockWaitCount.Enabled = true - // Transaction & Log Metrics (RDS equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionActiveCount.Enabled = true // RDS: Active Transactions - cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushRate.Enabled = true // RDS: Log Flushes/sec - cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushWaitRate.Enabled = true // Log IO bottleneck - cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogUsage.Enabled = true // RDS: TransactionLogUsage + // Windows-only metrics: These use Windows Performance Monitor counters (via recorders.go) + // that are unavailable on Linux. The SQL query fetches the data from sys.dm_os_performance_counters + // but scraper.go does not process them on the direct-connect (Linux) path. + isWindows := translatorcontext.CurrentContext().Os() == translatorconfig.OS_TYPE_WINDOWS + cfg.MetricsBuilderConfig.Metrics.SqlserverLockWaitTimeAvg.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverPageCheckpointFlushRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverPageLazyWriteRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverPageOperationRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverPageSplitRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionWriteRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushDataRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogFlushWaitRate.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogGrowthCount.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogShrinkCount.Enabled = isWindows + cfg.MetricsBuilderConfig.Metrics.SqlserverTransactionLogUsage.Enabled = isWindows - // Database I/O Metrics (RDS: ReadIOPS, WriteIOPS, ReadThroughput, WriteThroughput equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIo.Enabled = true // Per-database I/O - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseLatency.Enabled = true // Per-database latency - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseOperations.Enabled = true // I/O operations - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIoStallQueued.Enabled = true // Resource Governor I/O queue wait time - - // Connection & Workload Metrics (RDS equivalents) - cfg.MetricsBuilderConfig.Metrics.SqlserverLoginRate.Enabled = true // RDS: LoginFailures (partial) - cfg.MetricsBuilderConfig.Metrics.SqlserverLogoutRate.Enabled = true // Connection churn - cfg.MetricsBuilderConfig.Metrics.SqlserverSessionCount.Enabled = true // Active sessions by state + // Database I/O Metrics + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIo.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseLatency.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseOperations.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseIoStallQueued.Enabled = true + // Connection & Workload Metrics + cfg.MetricsBuilderConfig.Metrics.SqlserverLoginRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverLogoutRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverSessionCount.Enabled = true // Index & Query Performance Metrics - cfg.MetricsBuilderConfig.Metrics.SqlserverIndexSearchRate.Enabled = true // Index usage - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseFullScanRate.Enabled = true // Table scan indicator (performance issue) - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseExecutionErrors.Enabled = true // RDS: Errors/sec + cfg.MetricsBuilderConfig.Metrics.SqlserverIndexSearchRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseFullScanRate.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseExecutionErrors.Enabled = true // Optional: TempDB Metrics (useful for workload analysis) - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbSpace.Enabled = true // TempDB space usage - cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbVersionStoreSize.Enabled = true // Version store size + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbSpace.Enabled = true + cfg.MetricsBuilderConfig.Metrics.SqlserverDatabaseTempdbVersionStoreSize.Enabled = true cfg.LogsBuilderConfig.Events.DbServerQuerySample.Enabled = true cfg.LogsBuilderConfig.Events.DbServerTopQuery.Enabled = true diff --git a/translator/translate/otel/receiver/sqlserver/translator_test.go b/translator/translate/otel/receiver/sqlserver/translator_test.go index e16b3de4f6a..765e9046b9f 100644 --- a/translator/translate/otel/receiver/sqlserver/translator_test.go +++ b/translator/translate/otel/receiver/sqlserver/translator_test.go @@ -13,6 +13,7 @@ package sqlserver import ( + "runtime" "testing" "time" @@ -64,50 +65,74 @@ func TestTranslator_Translate_Localhost(t *testing.T) { assert.Equal(t, 921600, c.TopQueryCollection.MaxQueryPlanSize) // 900KB default // Metrics that are disabled-by-default in the receiver but required for DBI - // console parity with RDS Performance Insights. m := c.MetricsBuilderConfig.Metrics - // Performance & Resource Metrics (RDS equivalents) - assert.True(t, m.SqlserverProcessesBlocked.Enabled) // RDS: BlockedTransactions - assert.True(t, m.SqlserverDeadlockRate.Enabled) // RDS: Deadlocks/sec - assert.True(t, m.SqlserverMemoryGrantsPendingCount.Enabled) // RDS: Memory Grants Pending - assert.True(t, m.SqlserverMemoryUsage.Enabled) // RDS: FreeableMemory (inverse) + // Performance & Resource Metrics + assert.True(t, m.SqlserverProcessesBlocked.Enabled) + assert.True(t, m.SqlserverDeadlockRate.Enabled) + assert.True(t, m.SqlserverMemoryGrantsPendingCount.Enabled) + assert.True(t, m.SqlserverMemoryUsage.Enabled) - // Page & Buffer Pool Metrics (RDS equivalents) - assert.True(t, m.SqlserverPageLookupRate.Enabled) // RDS: Page Lookups/sec - assert.True(t, m.SqlserverForwardedRecordsRate.Enabled) // Performance tuning metric - assert.True(t, m.SqlserverPageBufferCacheFreeListStallsRate.Enabled) // Memory pressure indicator + // Page & Buffer Pool Metrics + assert.True(t, m.SqlserverPageLookupRate.Enabled) + assert.True(t, m.SqlserverForwardedRecordsRate.Enabled) + assert.True(t, m.SqlserverPageBufferCacheFreeListStallsRate.Enabled) // Wait Statistics (RDS Performance Insights equivalents) - assert.True(t, m.SqlserverLatchWaitRate.Enabled) // Concurrency metric - assert.True(t, m.SqlserverLockTimeoutRate.Enabled) // Lock contention - assert.True(t, m.SqlserverLockWaitCount.Enabled) // Lock contention + assert.True(t, m.SqlserverLatchWaitRate.Enabled) + assert.True(t, m.SqlserverLockTimeoutRate.Enabled) + assert.True(t, m.SqlserverLockWaitCount.Enabled) - // Transaction & Log Metrics (RDS equivalents) - assert.True(t, m.SqlserverTransactionActiveCount.Enabled) // RDS: Active Transactions - assert.True(t, m.SqlserverTransactionLogFlushRate.Enabled) // RDS: Log Flushes/sec - assert.True(t, m.SqlserverTransactionLogFlushWaitRate.Enabled) // Log IO bottleneck - assert.True(t, m.SqlserverTransactionLogUsage.Enabled) // RDS: TransactionLogUsage + // Windows-only metrics: use Windows Performance Monitor counters unavailable on Linux + if runtime.GOOS == "windows" { + assert.True(t, m.SqlserverLockWaitTimeAvg.Enabled) + assert.True(t, m.SqlserverPageCheckpointFlushRate.Enabled) + assert.True(t, m.SqlserverPageLazyWriteRate.Enabled) + assert.True(t, m.SqlserverPageOperationRate.Enabled) + assert.True(t, m.SqlserverPageSplitRate.Enabled) + assert.True(t, m.SqlserverTransactionRate.Enabled) + assert.True(t, m.SqlserverTransactionWriteRate.Enabled) + assert.True(t, m.SqlserverTransactionLogFlushDataRate.Enabled) + assert.True(t, m.SqlserverTransactionLogFlushRate.Enabled) + assert.True(t, m.SqlserverTransactionLogFlushWaitRate.Enabled) + assert.True(t, m.SqlserverTransactionLogGrowthCount.Enabled) + assert.True(t, m.SqlserverTransactionLogShrinkCount.Enabled) + assert.True(t, m.SqlserverTransactionLogUsage.Enabled) + } else { + assert.False(t, m.SqlserverLockWaitTimeAvg.Enabled) + assert.False(t, m.SqlserverPageCheckpointFlushRate.Enabled) + assert.False(t, m.SqlserverPageLazyWriteRate.Enabled) + assert.False(t, m.SqlserverPageOperationRate.Enabled) + assert.False(t, m.SqlserverPageSplitRate.Enabled) + assert.False(t, m.SqlserverTransactionRate.Enabled) + assert.False(t, m.SqlserverTransactionWriteRate.Enabled) + assert.False(t, m.SqlserverTransactionLogFlushDataRate.Enabled) + assert.False(t, m.SqlserverTransactionLogFlushRate.Enabled) + assert.False(t, m.SqlserverTransactionLogFlushWaitRate.Enabled) + assert.False(t, m.SqlserverTransactionLogGrowthCount.Enabled) + assert.False(t, m.SqlserverTransactionLogShrinkCount.Enabled) + assert.False(t, m.SqlserverTransactionLogUsage.Enabled) + } - // Database I/O Metrics (RDS: ReadIOPS, WriteIOPS, ReadThroughput, WriteThroughput equivalents) - assert.True(t, m.SqlserverDatabaseIo.Enabled) // Per-database I/O - assert.True(t, m.SqlserverDatabaseLatency.Enabled) // Per-database latency - assert.True(t, m.SqlserverDatabaseOperations.Enabled) // I/O operations - assert.True(t, m.SqlserverDatabaseIoStallQueued.Enabled) // Resource Governor I/O queue wait time + // Database I/O Metrics + assert.True(t, m.SqlserverDatabaseIo.Enabled) + assert.True(t, m.SqlserverDatabaseLatency.Enabled) + assert.True(t, m.SqlserverDatabaseOperations.Enabled) + assert.True(t, m.SqlserverDatabaseIoStallQueued.Enabled) - // Connection & Workload Metrics (RDS equivalents) - assert.True(t, m.SqlserverLoginRate.Enabled) // RDS: LoginFailures (partial) - assert.True(t, m.SqlserverLogoutRate.Enabled) // Connection churn - assert.True(t, m.SqlserverSessionCount.Enabled) // Active sessions by state + // Connection & Workload Metrics + assert.True(t, m.SqlserverLoginRate.Enabled) + assert.True(t, m.SqlserverLogoutRate.Enabled) + assert.True(t, m.SqlserverSessionCount.Enabled) // Index & Query Performance Metrics - assert.True(t, m.SqlserverIndexSearchRate.Enabled) // Index usage - assert.True(t, m.SqlserverDatabaseFullScanRate.Enabled) // Table scan indicator (performance issue) - assert.True(t, m.SqlserverDatabaseExecutionErrors.Enabled) // RDS: Errors/sec + assert.True(t, m.SqlserverIndexSearchRate.Enabled) + assert.True(t, m.SqlserverDatabaseFullScanRate.Enabled) + assert.True(t, m.SqlserverDatabaseExecutionErrors.Enabled) // Optional: TempDB Metrics (useful for workload analysis) - assert.True(t, m.SqlserverDatabaseTempdbSpace.Enabled) // TempDB space usage - assert.True(t, m.SqlserverDatabaseTempdbVersionStoreSize.Enabled) // Version store size + assert.True(t, m.SqlserverDatabaseTempdbSpace.Enabled) + assert.True(t, m.SqlserverDatabaseTempdbVersionStoreSize.Enabled) } func TestTranslator_Translate_DefaultPort(t *testing.T) { From 7f75913101e8bd8df0ebf859e675deaa8c6cc9f8 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Fri, 31 Jul 2026 18:25:43 +0000 Subject: [PATCH 08/12] chore(dbi): tune SQL Server query sample limits Adjust SQL Server query sample configuration to optimize resource usage: - Increase MaxRowsPerQuery from 500 to 5000 (aligns with PostgreSQL) - Decrease MaxQuerySampleCount from 5000 to 1000 (conservative limit) This balances query plan collection with CloudWatch Logs limits while maintaining the existing gzip+base64 compression for XML ShowPlan data. --- translator/translate/otel/receiver/sqlserver/translator.go | 4 ++-- .../translate/otel/receiver/sqlserver/translator_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/translator/translate/otel/receiver/sqlserver/translator.go b/translator/translate/otel/receiver/sqlserver/translator.go index 67c119611fe..a04466db25e 100644 --- a/translator/translate/otel/receiver/sqlserver/translator.go +++ b/translator/translate/otel/receiver/sqlserver/translator.go @@ -133,10 +133,10 @@ func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { cfg.LogsBuilderConfig.Events.DbServerQuerySample.Enabled = true cfg.LogsBuilderConfig.Events.DbServerTopQuery.Enabled = true - cfg.QuerySample.MaxRowsPerQuery = 500 + cfg.QuerySample.MaxRowsPerQuery = 5000 cfg.TopQueryCollection.CollectionInterval = t.topQueryInterval cfg.TopQueryCollection.TopQueryCount = 200 - cfg.TopQueryCollection.MaxQuerySampleCount = 5000 + cfg.TopQueryCollection.MaxQuerySampleCount = 1000 // Query Plan Caching: Controls caching behavior for SQL Server XML ShowPlan data // Plans are automatically compressed (always-on) to fit within CloudWatch Logs 1MB limit diff --git a/translator/translate/otel/receiver/sqlserver/translator_test.go b/translator/translate/otel/receiver/sqlserver/translator_test.go index 765e9046b9f..74a59447af2 100644 --- a/translator/translate/otel/receiver/sqlserver/translator_test.go +++ b/translator/translate/otel/receiver/sqlserver/translator_test.go @@ -54,9 +54,9 @@ func TestTranslator_Translate_Localhost(t *testing.T) { assert.True(t, c.LogsBuilderConfig.Events.DbServerTopQuery.Enabled) // DB Load / Top SQL tuning (match the mysql translator's values). - assert.Equal(t, uint64(500), c.QuerySample.MaxRowsPerQuery) + assert.Equal(t, uint64(5000), c.QuerySample.MaxRowsPerQuery) assert.Equal(t, uint(200), c.TopQueryCollection.TopQueryCount) - assert.Equal(t, uint(5000), c.TopQueryCollection.MaxQuerySampleCount) + assert.Equal(t, uint(1000), c.TopQueryCollection.MaxQuerySampleCount) assert.Equal(t, 60*time.Second, c.TopQueryCollection.CollectionInterval) // Query Plan Caching: verify all 3 fields (compression is always-on in receiver). From d8e127a34d408686962b4e503fe9993d76936b82 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Fri, 31 Jul 2026 18:35:53 +0000 Subject: [PATCH 09/12] chore(dbi): tune MySQL query sample limits Adjust MySQL query sample configuration to optimize resource usage: - Increase MaxRowsPerQuery from 500 to 5000 (aligns with PostgreSQL) - Decrease MaxQuerySampleCount from 5000 to 1000 (conservative limit) This balances query plan collection with CloudWatch Logs limits. --- translator/translate/otel/receiver/mysql/translator.go | 4 ++-- translator/translate/otel/receiver/mysql/translator_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/translator/translate/otel/receiver/mysql/translator.go b/translator/translate/otel/receiver/mysql/translator.go index 9a4e12ea93e..e2c573c9777 100644 --- a/translator/translate/otel/receiver/mysql/translator.go +++ b/translator/translate/otel/receiver/mysql/translator.go @@ -85,11 +85,11 @@ func (t *translator) Translate(_ *confmap.Conf) (component.Config, error) { cfg.LogsBuilderConfig.Events.DbServerQuerySample.Enabled = true cfg.LogsBuilderConfig.Events.DbServerTopQuery.Enabled = true - cfg.QuerySampleCollection.MaxRowsPerQuery = 500 + cfg.QuerySampleCollection.MaxRowsPerQuery = 5000 cfg.TopQueryCollection.CollectionInterval = t.topQueryInterval cfg.TopQueryCollection.TopQueryCount = 200 - cfg.TopQueryCollection.MaxQuerySampleCount = 5000 + cfg.TopQueryCollection.MaxQuerySampleCount = 1000 cfg.TopQueryCollection.QueryPlanCacheSize = 1000 cfg.TopQueryCollection.QueryPlanCacheTTL = time.Hour diff --git a/translator/translate/otel/receiver/mysql/translator_test.go b/translator/translate/otel/receiver/mysql/translator_test.go index 587b13f02d3..b6f1d7fbec7 100644 --- a/translator/translate/otel/receiver/mysql/translator_test.go +++ b/translator/translate/otel/receiver/mysql/translator_test.go @@ -37,9 +37,9 @@ func TestTranslator_Translate_Localhost(t *testing.T) { assert.True(t, mysqlCfg.TLS.Insecure) assert.True(t, mysqlCfg.LogsBuilderConfig.Events.DbServerQuerySample.Enabled) assert.True(t, mysqlCfg.LogsBuilderConfig.Events.DbServerTopQuery.Enabled) - assert.Equal(t, uint64(500), mysqlCfg.QuerySampleCollection.MaxRowsPerQuery) + assert.Equal(t, uint64(5000), mysqlCfg.QuerySampleCollection.MaxRowsPerQuery) assert.Equal(t, uint64(200), mysqlCfg.TopQueryCollection.TopQueryCount) - assert.Equal(t, uint64(5000), mysqlCfg.TopQueryCollection.MaxQuerySampleCount) + assert.Equal(t, uint64(1000), mysqlCfg.TopQueryCollection.MaxQuerySampleCount) assert.Equal(t, 1000, mysqlCfg.TopQueryCollection.QueryPlanCacheSize) assert.Equal(t, time.Hour, mysqlCfg.TopQueryCollection.QueryPlanCacheTTL) assert.Equal(t, 60*time.Second, mysqlCfg.TopQueryCollection.CollectionInterval) From 52659b2a3a55bff9c8aed8c5c7def29606a8efbd Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Wed, 5 Aug 2026 20:01:27 +0000 Subject: [PATCH 10/12] fix(workload-discovery): Resolve named instance ports on Windows via registry On Windows, SQL Server named instances store their TCP port in the registry rather than passing it via command-line flags. The workload discovery tool was falling back to the default port 1433 for all instances, causing incorrect port reporting for named instances. Add a Windows-specific registry port extractor that: 1. Extracts the instance name from the process command line (-s flag) 2. Resolves the instance name to its registry ID via Instance Names\SQL 3. Reads the TCP port from SuperSocketNetLib\Tcp\IPAll (static or dynamic) The extractor chain on Windows is now: registry -> cmdline -> env -> default. On Linux/other platforms, behavior is unchanged: cmdline -> env -> default. --- internal/detector/sqlserver/extract/port.go | 13 +- .../detector/sqlserver/extract/port_other.go | 14 ++ .../sqlserver/extract/port_windows.go | 126 ++++++++++++++++++ .../sqlserver/extract/port_windows_test.go | 65 +++++++++ 4 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 internal/detector/sqlserver/extract/port_other.go create mode 100644 internal/detector/sqlserver/extract/port_windows.go create mode 100644 internal/detector/sqlserver/extract/port_windows_test.go diff --git a/internal/detector/sqlserver/extract/port.go b/internal/detector/sqlserver/extract/port.go index 975ba1fb0fb..9faa7454829 100644 --- a/internal/detector/sqlserver/extract/port.go +++ b/internal/detector/sqlserver/extract/port.go @@ -22,15 +22,14 @@ type portExtractor struct { subExtractors []detector.PortExtractor } -// NewPortExtractor creates a port extractor that attempts to find the SQL Server port -// from command line arguments (-p flag) or environment variables (MSSQL_TCP_PORT). -// Falls back to the default SQL Server port 1433. +// NewPortExtractor creates a port extractor that attempts to find the SQL Server port. +// On Windows, it first checks the registry to resolve named instance ports. +// Then it tries command line arguments (-p flag) and environment variables (MSSQL_TCP_PORT). +// Falls back to the default SQL Server port 1433 if all sources fail. func NewPortExtractor() detector.PortExtractor { + extractors := append(platformPortExtractors(), &cmdlinePortExtractor{}, &envPortExtractor{}) return &portExtractor{ - subExtractors: []detector.PortExtractor{ - &cmdlinePortExtractor{}, - &envPortExtractor{}, - }, + subExtractors: extractors, } } diff --git a/internal/detector/sqlserver/extract/port_other.go b/internal/detector/sqlserver/extract/port_other.go new file mode 100644 index 00000000000..24a1e880611 --- /dev/null +++ b/internal/detector/sqlserver/extract/port_other.go @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +//go:build !windows + +package extract + +import "github.com/aws/amazon-cloudwatch-agent/internal/detector" + +// platformPortExtractors returns an empty slice on non-Windows platforms. +// Linux SQL Server uses -p flag or MSSQL_TCP_PORT which are handled by the common extractors. +func platformPortExtractors() []detector.PortExtractor { + return nil +} diff --git a/internal/detector/sqlserver/extract/port_windows.go b/internal/detector/sqlserver/extract/port_windows.go new file mode 100644 index 00000000000..e4a5e3c75c2 --- /dev/null +++ b/internal/detector/sqlserver/extract/port_windows.go @@ -0,0 +1,126 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package extract + +import ( + "context" + "fmt" + "strconv" + "strings" + + "golang.org/x/sys/windows/registry" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector" + "github.com/aws/amazon-cloudwatch-agent/internal/detector/util" +) + +const ( + instanceNameFlag = "-s" + defaultInstanceName = "MSSQLSERVER" + sqlServerRegBasePath = `SOFTWARE\Microsoft\Microsoft SQL Server` +) + +// platformPortExtractors returns Windows-specific port extractors. +// The registry extractor correctly resolves ports for named instances. +func platformPortExtractors() []detector.PortExtractor { + return []detector.PortExtractor{®istryPortExtractor{}} +} + +// registryPortExtractor reads the TCP port from the Windows registry for a SQL Server instance. +// Each instance stores its port in: +// HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer\SuperSocketNetLib\Tcp\IPAll +type registryPortExtractor struct{} + +func (e *registryPortExtractor) Extract(ctx context.Context, process detector.Process) (int, error) { + instanceName := extractInstanceName(ctx, process) + + instanceID, err := resolveInstanceID(instanceName) + if err != nil { + return 0, err + } + + return readPortFromRegistry(instanceID) +} + +// extractInstanceName gets the SQL Server instance name from the process command line. +// Named instances are started with -s INSTANCENAME flag. Default instance uses MSSQLSERVER. +func extractInstanceName(ctx context.Context, process detector.Process) string { + args, err := process.CmdlineSliceWithContext(ctx) + if err != nil { + return defaultInstanceName + } + + for i, arg := range args { + lower := strings.ToLower(arg) + if lower == instanceNameFlag && i+1 < len(args) { + return strings.ToUpper(args[i+1]) + } + if strings.HasPrefix(lower, instanceNameFlag) && len(arg) > len(instanceNameFlag) { + return strings.ToUpper(arg[len(instanceNameFlag):]) + } + } + + return defaultInstanceName +} + +// resolveInstanceID maps an instance name (e.g., "MSSQLSERVER" or "YOURDBINSTANCE2") +// to its registry ID (e.g., "MSSQL17.MSSQLSERVER") by reading +// HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL +func resolveInstanceID(instanceName string) (string, error) { + keyPath := sqlServerRegBasePath + `\Instance Names\SQL` + key, err := registry.OpenKey(registry.LOCAL_MACHINE, keyPath, registry.QUERY_VALUE) + if err != nil { + return "", fmt.Errorf("failed to open registry key %s: %w", keyPath, err) + } + defer key.Close() + + instanceID, _, err := key.GetStringValue(instanceName) + if err != nil { + return "", fmt.Errorf("failed to read instance %s from registry: %w", instanceName, err) + } + + return instanceID, nil +} + +// readPortFromRegistry reads the TCP port for a given instance ID. +// Checks TcpPort (static) first, then TcpDynamicPorts (dynamic). +func readPortFromRegistry(instanceID string) (int, error) { + keyPath := fmt.Sprintf(`%s\%s\MSSQLServer\SuperSocketNetLib\Tcp\IPAll`, sqlServerRegBasePath, instanceID) + key, err := registry.OpenKey(registry.LOCAL_MACHINE, keyPath, registry.QUERY_VALUE) + if err != nil { + return 0, fmt.Errorf("failed to open registry key %s: %w", keyPath, err) + } + defer key.Close() + + if port, err := readPortValue(key, "TcpPort"); err == nil { + return port, nil + } + + if port, err := readPortValue(key, "TcpDynamicPorts"); err == nil { + return port, nil + } + + return 0, detector.ErrExtractPort +} + +func readPortValue(key registry.Key, valueName string) (int, error) { + val, _, err := key.GetStringValue(valueName) + if err != nil { + return 0, err + } + val = strings.TrimSpace(val) + if val == "" { + return 0, detector.ErrExtractPort + } + port, err := strconv.Atoi(val) + if err != nil { + return 0, err + } + if !util.IsValidPort(port) { + return 0, detector.ErrInvalidPort + } + return port, nil +} diff --git a/internal/detector/sqlserver/extract/port_windows_test.go b/internal/detector/sqlserver/extract/port_windows_test.go new file mode 100644 index 00000000000..ea01d8f5e2f --- /dev/null +++ b/internal/detector/sqlserver/extract/port_windows_test.go @@ -0,0 +1,65 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package extract + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/aws/amazon-cloudwatch-agent/internal/detector/detectortest" +) + +func TestExtractInstanceName(t *testing.T) { + ctx := context.Background() + + tests := map[string]struct { + cmdline []string + cmdlineErr error + wantInstance string + }{ + "DefaultInstance/NoCmdlineFlag": { + cmdline: []string{"sqlservr"}, + wantInstance: "MSSQLSERVER", + }, + "DefaultInstance/CmdlineError": { + cmdlineErr: assert.AnError, + wantInstance: "MSSQLSERVER", + }, + "NamedInstance/SeparateArg": { + cmdline: []string{"sqlservr", "-s", "YOURDBINSTANCE2"}, + wantInstance: "YOURDBINSTANCE2", + }, + "NamedInstance/AttachedArg": { + cmdline: []string{"sqlservr", "-sYOURDBINSTANCE2"}, + wantInstance: "YOURDBINSTANCE2", + }, + "NamedInstance/LowercaseFlag": { + cmdline: []string{"sqlservr", "-s", "myinstance"}, + wantInstance: "MYINSTANCE", + }, + "NamedInstance/WithOtherFlags": { + cmdline: []string{"sqlservr", "-f", "-s", "INST2", "-T", "3608"}, + wantInstance: "INST2", + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + mp := new(detectortest.MockProcess) + if tt.cmdlineErr != nil { + mp.On("CmdlineSliceWithContext", ctx).Return(nil, tt.cmdlineErr) + } else { + mp.On("CmdlineSliceWithContext", ctx).Return(tt.cmdline, nil) + } + + got := extractInstanceName(ctx, mp) + assert.Equal(t, tt.wantInstance, got) + mp.AssertExpectations(t) + }) + } +} From effecd9adc0184836095cd399cb2933ad2c94909 Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Wed, 5 Aug 2026 20:17:52 +0000 Subject: [PATCH 11/12] fix(dbi): Decode SQL Server ERRORLOG as UTF-16LE on Windows Windows SQL Server writes its ERRORLOG in UTF-16LE encoding, causing server log entries to appear as garbled null-interleaved text in CloudWatch Logs (e.g. 'S\u0000t\u0000a\u0000r\u0000t\u0000i\u0000n\u0000g'). Add a runtime.GOOS check to set the filelog receiver encoding to 'utf-16le' when running on Windows. On Linux, SQL Server writes ERRORLOG in UTF-8, so no encoding override is needed. Verified on both instances: - Windows (i-01992cda09d257426): server logs now appear as readable text - Linux (i-0c4670d5ab711c0dd): server logs already UTF-8, no issue --- .../pipeline/opentelemetry/databaseinsights/translator.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go index e6156c05a79..c1e211c40d3 100644 --- a/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go +++ b/translator/translate/otel/pipeline/opentelemetry/databaseinsights/translator.go @@ -5,6 +5,7 @@ package databaseinsights import ( "fmt" + "runtime" "strconv" "strings" "time" @@ -283,6 +284,10 @@ func (t *dbiTranslator) serverLogReceiver() common.ComponentTranslator { filelog.WithSeverityPattern(buildSqlServerSeverityPattern()), filelog.WithSeverityMapping(sqlserverLogSeverityMapping), ) + // Windows SQL Server writes ERRORLOG in UTF-16LE encoding. + if runtime.GOOS == "windows" { + opts = append(opts, filelog.WithEncoding("utf-16le")) + } } return filelog.NewTranslator(opts...) } From b7e259f4cd5559c661bb72cd8c2e90f38d9f57ba Mon Sep 17 00:00:00 2001 From: Kirsty Larsen Date: Thu, 6 Aug 2026 11:57:28 +0000 Subject: [PATCH 12/12] chore(dbi): update mysqlreceiver to latest dbi-mysql branch (83b5027c386b) Update go.mod to point to the latest commit on the upstream dbi-mysql branch which includes PR #617 (InnoDB deadlocks and transaction metrics). --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ffa5f8fa648..72b0caaa8d5 100644 --- a/go.mod +++ b/go.mod @@ -69,7 +69,7 @@ replace ( github.com/open-telemetry/opentelemetry-collector-contrib/receiver/awsekshyperpodreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/awsekshyperpodreceiver v0.0.0-20260717191209-ee093fbfffbd github.com/open-telemetry/opentelemetry-collector-contrib/receiver/awsxrayreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/awsxrayreceiver v0.0.0-20260717191209-ee093fbfffbd github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jmxreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/jmxreceiver v0.0.0-20260717191209-ee093fbfffbd - github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260728131824-bed4560687ee + github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mysqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260730161852-83b5027c386b github.com/open-telemetry/opentelemetry-collector-contrib/receiver/postgresqlreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver => github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd // Cherry-pick of upstream Query XML support for windowseventlogreceiver https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/39055 diff --git a/go.sum b/go.sum index 13472f85f46..75530c8fa3b 100644 --- a/go.sum +++ b/go.sum @@ -274,8 +274,8 @@ github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/awsxrayr github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/awsxrayreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:gNDpUc9eYHKy9YqGYK8toPIo3QZKdYQFLnaVQDA32A0= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/jmxreceiver v0.0.0-20260717191209-ee093fbfffbd h1:AF4G2iJwaLeBivwjWMppWYbmfObc+foQws5fetLUWxk= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/jmxreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:wQV77sHJJdUMIvbJna8LjlNb0omEdiVSrwQnoVAlTMM= -github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260728131824-bed4560687ee h1:XELS9NH+v8xvMQS49SckY5HWDfqrYNzUPQT62NT4QgY= -github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260728131824-bed4560687ee/go.mod h1:NAyuB/xYR3FsPuegcRvVeStWW83y5oUQhekzT856urI= +github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260730161852-83b5027c386b h1:AHEwT0RHOaEDz0t5WrH7OkQH93I2zoFaM90qR01oLII= +github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/mysqlreceiver v0.0.0-20260730161852-83b5027c386b/go.mod h1:NAyuB/xYR3FsPuegcRvVeStWW83y5oUQhekzT856urI= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd h1:Q0XNkIPZEiIlknoP0X0PxoKVmlKR0itxyHQjZUkFTsg= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/postgresqlreceiver v0.0.0-20260717191209-ee093fbfffbd/go.mod h1:DdKZOg4y/ac/f/ENvYWWg6e6r+INsAkx6DqRXzps1TU= github.com/amazon-contributing/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.0.0-20260717191209-ee093fbfffbd h1:gguRr06gAfXYB1kxUZH7VaZobUauXRX+uNWGA0hsGx4=