From 5e3d7b8a1669073e114219917bea6db223ebbaec Mon Sep 17 00:00:00 2001 From: Marcin Lewandowski Date: Wed, 3 Mar 2021 20:37:06 +0100 Subject: [PATCH] Input plugin for RavenDB (#8834) --- README.md | 1 + etc/telegraf.conf | 32 ++ plugins/inputs/all/all.go | 1 + plugins/inputs/ravendb/README.md | 216 +++++++++ plugins/inputs/ravendb/ravendb.go | 425 ++++++++++++++++++ plugins/inputs/ravendb/ravendb_dto.go | 199 ++++++++ plugins/inputs/ravendb/ravendb_test.go | 393 ++++++++++++++++ .../ravendb/testdata/collections_full.json | 19 + .../ravendb/testdata/collections_min.json | 19 + .../ravendb/testdata/databases_full.json | 49 ++ .../ravendb/testdata/databases_min.json | 49 ++ .../inputs/ravendb/testdata/indexes_full.json | 25 ++ .../inputs/ravendb/testdata/indexes_min.json | 25 ++ .../inputs/ravendb/testdata/server_full.json | 73 +++ .../inputs/ravendb/testdata/server_min.json | 72 +++ 15 files changed, 1598 insertions(+) create mode 100644 plugins/inputs/ravendb/README.md create mode 100644 plugins/inputs/ravendb/ravendb.go create mode 100644 plugins/inputs/ravendb/ravendb_dto.go create mode 100644 plugins/inputs/ravendb/ravendb_test.go create mode 100644 plugins/inputs/ravendb/testdata/collections_full.json create mode 100644 plugins/inputs/ravendb/testdata/collections_min.json create mode 100644 plugins/inputs/ravendb/testdata/databases_full.json create mode 100644 plugins/inputs/ravendb/testdata/databases_min.json create mode 100644 plugins/inputs/ravendb/testdata/indexes_full.json create mode 100644 plugins/inputs/ravendb/testdata/indexes_min.json create mode 100644 plugins/inputs/ravendb/testdata/server_full.json create mode 100644 plugins/inputs/ravendb/testdata/server_min.json diff --git a/README.md b/README.md index 3e2d332fb..2e88d83bb 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,7 @@ For documentation on the latest development code see the [documentation index][d * [rabbitmq](./plugins/inputs/rabbitmq) * [raindrops](./plugins/inputs/raindrops) * [ras](./plugins/inputs/ras) +* [ravendb](./plugins/inputs/ravendb) * [redfish](./plugins/inputs/redfish) * [redis](./plugins/inputs/redis) * [rethinkdb](./plugins/inputs/rethinkdb) diff --git a/etc/telegraf.conf b/etc/telegraf.conf index 425e6d758..c70b1d2f9 100644 --- a/etc/telegraf.conf +++ b/etc/telegraf.conf @@ -5065,6 +5065,38 @@ # ## Default: /var/lib/rasdaemon/ras-mc_event.db # # db_path = "" +# [[inputs.ravendb]] +# ## Node URL and port that RavenDB is listening on. +# url = "https://localhost:8080" +# +# ## RavenDB X509 client certificate setup +# tls_cert = "/etc/telegraf/raven.crt" +# tls_key = "/etc/telegraf/raven.key" +# +# ## Optional request timeout +# ## +# ## Timeout, specifies the amount of time to wait +# ## for a server's response headers after fully writing the request and +# ## time limit for requests made by this client. +# # timeout = "5s" +# +# ## List of statistics which are collected +# # At least one is required +# # Allowed values: server, databases, indexes, collections +# +# # stats_include = ["server", "databases", "indexes", "collections"] +# +# ## List of db where database stats are collected +# ## If empty, all db are concerned +# # db_stats_dbs = [] +# +# ## List of db where index status are collected +# ## If empty, all indexes from all db are concerned +# # index_stats_dbs = [] +# +# ## List of db where collection status are collected +# ## If empty, all collections from all db are concerned +# # collection_stats_dbs = [] # # Read CPU, Fans, Powersupply and Voltage metrics of hardware server through redfish APIs # [[inputs.redfish]] diff --git a/plugins/inputs/all/all.go b/plugins/inputs/all/all.go index 595be84ca..65d8d5254 100644 --- a/plugins/inputs/all/all.go +++ b/plugins/inputs/all/all.go @@ -147,6 +147,7 @@ import ( _ "github.com/influxdata/telegraf/plugins/inputs/rabbitmq" _ "github.com/influxdata/telegraf/plugins/inputs/raindrops" _ "github.com/influxdata/telegraf/plugins/inputs/ras" + _ "github.com/influxdata/telegraf/plugins/inputs/ravendb" _ "github.com/influxdata/telegraf/plugins/inputs/redfish" _ "github.com/influxdata/telegraf/plugins/inputs/redis" _ "github.com/influxdata/telegraf/plugins/inputs/rethinkdb" diff --git a/plugins/inputs/ravendb/README.md b/plugins/inputs/ravendb/README.md new file mode 100644 index 000000000..b40850ab5 --- /dev/null +++ b/plugins/inputs/ravendb/README.md @@ -0,0 +1,216 @@ +# RavenDB Input Plugin + +Reads metrics from RavenDB servers via monitoring endpoints APIs. + +Requires RavenDB Server 5.2+. + +### Configuration + +The following is an example config for RavenDB. **Note:** The client certificate used should have `Operator` permissions on the cluster. + +```toml +[[inputs.ravendb]] + ## Node URL and port that RavenDB is listening on + url = "https://localhost:8080" + + ## RavenDB X509 client certificate setup + tls_cert = "/etc/telegraf/raven.crt" + tls_key = "/etc/telegraf/raven.key" + + ## Optional request timeout + ## + ## Timeout, specifies the amount of time to wait + ## for a server's response headers after fully writing the request and + ## time limit for requests made by this client + # timeout = "5s" + + ## List of statistics which are collected + # At least one is required + # Allowed values: server, databases, indexes, collections + # + # stats_include = ["server", "databases", "indexes", "collections"] + + ## List of db where database stats are collected + ## If empty, all db are concerned + # db_stats_dbs = [] + + ## List of db where index status are collected + ## If empty, all indexes from all db are concerned + # index_stats_dbs = [] + + ## List of db where collection status are collected + ## If empty, all collections from all db are concerned + # collection_stats_dbs = [] +``` + +### Metrics + +- ravendb_server + - tags: + - url + - node_tag + - cluster_id + - public_server_url (optional) + - fields: + - backup_current_number_of_running_backups + - backup_max_number_of_concurrent_backups + - certificate_server_certificate_expiration_left_in_sec (optional) + - certificate_well_known_admin_certificates (optional, separated by ';') + - cluster_current_term + - cluster_index + - cluster_node_state + - 0 -> Passive + - 1 -> Candidate + - 2 -> Follower + - 3 -> LeaderElect + - 4 -> Leader + - config_public_tcp_server_urls (optional, separated by ';') + - config_server_urls + - config_tcp_server_urls (optional, separated by ';') + - cpu_assigned_processor_count + - cpu_machine_usage + - cpu_machine_io_wait (optional) + - cpu_process_usage + - cpu_processor_count + - cpu_thread_pool_available_worker_threads + - cpu_thread_pool_available_completion_port_threads + - databases_loaded_count + - databases_total_count + - disk_remaining_storage_space_percentage + - disk_system_store_used_data_file_size_in_mb + - disk_system_store_total_data_file_size_in_mb + - disk_total_free_space_in_mb + - license_expiration_left_in_sec (optional) + - license_max_cores + - license_type + - license_utilized_cpu_cores + - memory_allocated_in_mb + - memory_installed_in_mb + - memory_low_memory_severity + - 0 -> None + - 1 -> Low + - 2 -> Extremely Low + - memory_physical_in_mb + - memory_total_dirty_in_mb + - memory_total_swap_size_in_mb + - memory_total_swap_usage_in_mb + - memory_working_set_swap_usage_in_mb + - network_concurrent_requests_count + - network_last_authorized_non_cluster_admin_request_time_in_sec (optional) + - network_last_request_time_in_sec (optional) + - network_requests_per_sec + - network_tcp_active_connections + - network_total_requests + - server_full_version + - server_process_id + - server_version + - uptime_in_sec + +- ravendb_databases + - tags: + - url + - database_name + - database_id + - node_tag + - public_server_url (optional) + - fields: + - counts_alerts + - counts_attachments + - counts_documents + - counts_performance_hints + - counts_rehabs + - counts_replication_factor + - counts_revisions + - counts_unique_attachments + - statistics_doc_puts_per_sec + - statistics_map_index_indexes_per_sec + - statistics_map_reduce_index_mapped_per_sec + - statistics_map_reduce_index_reduced_per_sec + - statistics_request_average_duration_in_ms + - statistics_requests_count + - statistics_requests_per_sec + - indexes_auto_count + - indexes_count + - indexes_disabled_count + - indexes_errors_count + - indexes_errored_count + - indexes_idle_count + - indexes_stale_count + - indexes_static_count + - storage_documents_allocated_data_file_in_mb + - storage_documents_used_data_file_in_mb + - storage_indexes_allocated_data_file_in_mb + - storage_indexes_used_data_file_in_mb + - storage_total_allocated_storage_file_in_mb + - storage_total_free_space_in_mb + - time_since_last_backup_in_sec (optional) + - uptime_in_sec + +- ravendb_indexes + - tags: + - database_name + - index_name + - node_tag + - public_server_url (optional) + - url + - fields + - errors + - is_invalid + - lock_mode + - Unlock + - LockedIgnore + - LockedError + - mapped_per_sec + - priority + - Low + - Normal + - High + - reduced_per_sec + - state + - Normal + - Disabled + - Idle + - Error + - status + - Running + - Paused + - Disabled + - time_since_last_indexing_in_sec (optional) + - time_since_last_query_in_sec (optional) + - type + - None + - AutoMap + - AutoMapReduce + - Map + - MapReduce + - Faulty + - JavaScriptMap + - JavaScriptMapReduce + +- ravendb_collections + - tags: + - collection_name + - database_name + - node_tag + - public_server_url (optional) + - url + - fields + - documents_count + - documents_size_in_bytes + - revisions_size_in_bytes + - tombstones_size_in_bytes + - total_size_in_bytes + +### Example output + +``` +> ravendb_server,cluster_id=07aecc42-9194-4181-999c-1c42450692c9,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 backup_current_number_of_running_backups=0i,backup_max_number_of_concurrent_backups=4i,certificate_server_certificate_expiration_left_in_sec=-1,cluster_current_term=2i,cluster_index=10i,cluster_node_state=4i,config_server_urls="http://127.0.0.1:8080",cpu_assigned_processor_count=8i,cpu_machine_usage=19.09944089456869,cpu_process_usage=0.16977205323024872,cpu_processor_count=8i,cpu_thread_pool_available_completion_port_threads=1000i,cpu_thread_pool_available_worker_threads=32763i,databases_loaded_count=1i,databases_total_count=1i,disk_remaining_storage_space_percentage=18i,disk_system_store_total_data_file_size_in_mb=35184372088832i,disk_system_store_used_data_file_size_in_mb=31379031064576i,disk_total_free_space_in_mb=42931i,license_expiration_left_in_sec=24079222.8772186,license_max_cores=256i,license_type="Enterprise",license_utilized_cpu_cores=8i,memory_allocated_in_mb=205i,memory_installed_in_mb=16384i,memory_low_memory_severity=0i,memory_physical_in_mb=16250i,memory_total_dirty_in_mb=0i,memory_total_swap_size_in_mb=0i,memory_total_swap_usage_in_mb=0i,memory_working_set_swap_usage_in_mb=0i,network_concurrent_requests_count=1i,network_last_request_time_in_sec=0.0058717,network_requests_per_sec=0.09916543455308825,network_tcp_active_connections=128i,network_total_requests=10i,server_full_version="5.2.0-custom-52",server_process_id=31044i,server_version="5.2",uptime_in_sec=56i 1613027977000000000 +> ravendb_databases,database_id=ced0edba-8f80-48b8-8e81-c3d2c6748ec3,database_name=db1,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 counts_alerts=0i,counts_attachments=17i,counts_documents=1059i,counts_performance_hints=0i,counts_rehabs=0i,counts_replication_factor=1i,counts_revisions=5475i,counts_unique_attachments=17i,indexes_auto_count=0i,indexes_count=7i,indexes_disabled_count=0i,indexes_errored_count=0i,indexes_errors_count=0i,indexes_idle_count=0i,indexes_stale_count=0i,indexes_static_count=7i,statistics_doc_puts_per_sec=0,statistics_map_index_indexes_per_sec=0,statistics_map_reduce_index_mapped_per_sec=0,statistics_map_reduce_index_reduced_per_sec=0,statistics_request_average_duration_in_ms=0,statistics_requests_count=0i,statistics_requests_per_sec=0,storage_documents_allocated_data_file_in_mb=140737488355328i,storage_documents_used_data_file_in_mb=74741020884992i,storage_indexes_allocated_data_file_in_mb=175921860444160i,storage_indexes_used_data_file_in_mb=120722940755968i,storage_total_allocated_storage_file_in_mb=325455441821696i,storage_total_free_space_in_mb=42931i,uptime_in_sec=54 1613027977000000000 +> ravendb_indexes,database_name=db1,host=DESKTOP-2OISR6D,index_name=Orders/Totals,node_tag=A,url=http://localhost:8080 errors=0i,is_invalid=false,lock_mode="Unlock",mapped_per_sec=0,priority="Normal",reduced_per_sec=0,state="Normal",status="Running",time_since_last_indexing_in_sec=45.4256655,time_since_last_query_in_sec=45.4304202,type="Map" 1613027977000000000 +> ravendb_collections,collection_name=@hilo,database_name=db1,host=DESKTOP-2OISR6D,node_tag=A,url=http://localhost:8080 documents_count=8i,documents_size_in_bytes=122880i,revisions_size_in_bytes=0i,tombstones_size_in_bytes=122880i,total_size_in_bytes=245760i 1613027977000000000 +``` + +### Contributors + +- Marcin Lewandowski (https://github.com/ml054/) +- Casey Barton (https://github.com/bartoncasey) \ No newline at end of file diff --git a/plugins/inputs/ravendb/ravendb.go b/plugins/inputs/ravendb/ravendb.go new file mode 100644 index 000000000..42b50d0d3 --- /dev/null +++ b/plugins/inputs/ravendb/ravendb.go @@ -0,0 +1,425 @@ +package ravendb + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "strings" + "sync" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/internal" + "github.com/influxdata/telegraf/internal/choice" + "github.com/influxdata/telegraf/plugins/common/tls" + "github.com/influxdata/telegraf/plugins/inputs" +) + +// defaultURL will set a default value that corresponds to the default value +// used by RavenDB +const defaultURL = "http://localhost:8080" + +const defaultTimeout = 5 + +// RavenDB defines the configuration necessary for gathering metrics, +// see the sample config for further details +type RavenDB struct { + URL string `toml:"url"` + Name string `toml:"name"` + + Timeout internal.Duration `toml:"timeout"` + + StatsInclude []string `toml:"stats_include"` + DbStatsDbs []string `toml:"db_stats_dbs"` + IndexStatsDbs []string `toml:"index_stats_dbs"` + CollectionStatsDbs []string `toml:"collection_stats_dbs"` + + tls.ClientConfig + + Log telegraf.Logger `toml:"-"` + + client *http.Client + requestUrlServer string + requestUrlDatabases string + requestUrlIndexes string + requestUrlCollection string +} + +var sampleConfig = ` + ## Node URL and port that RavenDB is listening on + url = "https://localhost:8080" + + ## RavenDB X509 client certificate setup + # tls_cert = "/etc/telegraf/raven.crt" + # tls_key = "/etc/telegraf/raven.key" + + ## Optional request timeout + ## + ## Timeout, specifies the amount of time to wait + ## for a server's response headers after fully writing the request and + ## time limit for requests made by this client + # timeout = "5s" + + ## List of statistics which are collected + # At least one is required + # Allowed values: server, databases, indexes, collections + # + # stats_include = ["server", "databases", "indexes", "collections"] + + ## List of db where database stats are collected + ## If empty, all db are concerned + # db_stats_dbs = [] + + ## List of db where index status are collected + ## If empty, all indexes from all db are concerned + # index_stats_dbs = [] + + ## List of db where collection status are collected + ## If empty, all collections from all db are concerned + # collection_stats_dbs = [] +` + +func (r *RavenDB) SampleConfig() string { + return sampleConfig +} + +func (r *RavenDB) Description() string { + return "Reads metrics from RavenDB servers via the Monitoring Endpoints" +} + +func (r *RavenDB) Gather(acc telegraf.Accumulator) error { + var wg sync.WaitGroup + + for _, statToCollect := range r.StatsInclude { + wg.Add(1) + + switch statToCollect { + case "server": + go func() { + defer wg.Done() + r.gatherServer(acc) + }() + case "databases": + go func() { + defer wg.Done() + r.gatherDatabases(acc) + }() + case "indexes": + go func() { + defer wg.Done() + r.gatherIndexes(acc) + }() + case "collections": + go func() { + defer wg.Done() + r.gatherCollections(acc) + }() + } + } + + wg.Wait() + + return nil +} + +func (r *RavenDB) ensureClient() error { + if r.client != nil { + return nil + } + + tlsCfg, err := r.ClientConfig.TLSConfig() + if err != nil { + return err + } + tr := &http.Transport{ + ResponseHeaderTimeout: r.Timeout.Duration, + TLSClientConfig: tlsCfg, + } + r.client = &http.Client{ + Transport: tr, + Timeout: r.Timeout.Duration, + } + + return nil +} + +func (r *RavenDB) requestJSON(u string, target interface{}) error { + req, err := http.NewRequest("GET", u, nil) + if err != nil { + return err + } + + resp, err := r.client.Do(req) + if err != nil { + return err + } + + defer resp.Body.Close() + + r.Log.Debugf("%s: %s", u, resp.Status) + if resp.StatusCode >= 400 { + return fmt.Errorf("invalid response code to request '%s': %d - %s", r.URL, resp.StatusCode, resp.Status) + } + + return json.NewDecoder(resp.Body).Decode(target) +} + +func (r *RavenDB) gatherServer(acc telegraf.Accumulator) { + serverResponse := &serverMetricsResponse{} + + err := r.requestJSON(r.requestUrlServer, &serverResponse) + if err != nil { + acc.AddError(err) + return + } + + tags := map[string]string{ + "cluster_id": serverResponse.Cluster.Id, + "node_tag": serverResponse.Cluster.NodeTag, + "url": r.URL, + } + + if serverResponse.Config.PublicServerUrl != nil { + tags["public_server_url"] = *serverResponse.Config.PublicServerUrl + } + + fields := map[string]interface{}{ + "backup_current_number_of_running_backups": serverResponse.Backup.CurrentNumberOfRunningBackups, + "backup_max_number_of_concurrent_backups": serverResponse.Backup.MaxNumberOfConcurrentBackups, + "certificate_server_certificate_expiration_left_in_sec": serverResponse.Certificate.ServerCertificateExpirationLeftInSec, + "cluster_current_term": serverResponse.Cluster.CurrentTerm, + "cluster_index": serverResponse.Cluster.Index, + "cluster_node_state": serverResponse.Cluster.NodeState, + "config_server_urls": strings.Join(serverResponse.Config.ServerUrls, ";"), + "cpu_assigned_processor_count": serverResponse.Cpu.AssignedProcessorCount, + "cpu_machine_io_wait": serverResponse.Cpu.MachineIoWait, + "cpu_machine_usage": serverResponse.Cpu.MachineUsage, + "cpu_process_usage": serverResponse.Cpu.ProcessUsage, + "cpu_processor_count": serverResponse.Cpu.ProcessorCount, + "cpu_thread_pool_available_worker_threads": serverResponse.Cpu.ThreadPoolAvailableWorkerThreads, + "cpu_thread_pool_available_completion_port_threads": serverResponse.Cpu.ThreadPoolAvailableCompletionPortThreads, + "databases_loaded_count": serverResponse.Databases.LoadedCount, + "databases_total_count": serverResponse.Databases.TotalCount, + "disk_remaining_storage_space_percentage": serverResponse.Disk.RemainingStorageSpacePercentage, + "disk_system_store_used_data_file_size_in_mb": serverResponse.Disk.SystemStoreUsedDataFileSizeInMb, + "disk_system_store_total_data_file_size_in_mb": serverResponse.Disk.SystemStoreTotalDataFileSizeInMb, + "disk_total_free_space_in_mb": serverResponse.Disk.TotalFreeSpaceInMb, + "license_expiration_left_in_sec": serverResponse.License.ExpirationLeftInSec, + "license_max_cores": serverResponse.License.MaxCores, + "license_type": serverResponse.License.Type, + "license_utilized_cpu_cores": serverResponse.License.UtilizedCpuCores, + "memory_allocated_in_mb": serverResponse.Memory.AllocatedMemoryInMb, + "memory_installed_in_mb": serverResponse.Memory.InstalledMemoryInMb, + "memory_low_memory_severity": serverResponse.Memory.LowMemorySeverity, + "memory_physical_in_mb": serverResponse.Memory.PhysicalMemoryInMb, + "memory_total_dirty_in_mb": serverResponse.Memory.TotalDirtyInMb, + "memory_total_swap_size_in_mb": serverResponse.Memory.TotalSwapSizeInMb, + "memory_total_swap_usage_in_mb": serverResponse.Memory.TotalSwapUsageInMb, + "memory_working_set_swap_usage_in_mb": serverResponse.Memory.WorkingSetSwapUsageInMb, + "network_concurrent_requests_count": serverResponse.Network.ConcurrentRequestsCount, + "network_last_authorized_non_cluster_admin_request_time_in_sec": serverResponse.Network.LastAuthorizedNonClusterAdminRequestTimeInSec, + "network_last_request_time_in_sec": serverResponse.Network.LastRequestTimeInSec, + "network_requests_per_sec": serverResponse.Network.RequestsPerSec, + "network_tcp_active_connections": serverResponse.Network.TcpActiveConnections, + "network_total_requests": serverResponse.Network.TotalRequests, + "server_full_version": serverResponse.ServerFullVersion, + "server_process_id": serverResponse.ServerProcessId, + "server_version": serverResponse.ServerVersion, + "uptime_in_sec": serverResponse.UpTimeInSec, + } + + if serverResponse.Config.TcpServerUrls != nil { + fields["config_tcp_server_urls"] = strings.Join(serverResponse.Config.TcpServerUrls, ";") + } + + if serverResponse.Config.PublicTcpServerUrls != nil { + fields["config_public_tcp_server_urls"] = strings.Join(serverResponse.Config.PublicTcpServerUrls, ";") + } + + if serverResponse.Certificate.WellKnownAdminCertificates != nil { + fields["certificate_well_known_admin_certificates"] = strings.Join(serverResponse.Certificate.WellKnownAdminCertificates, ";") + } + + acc.AddFields("ravendb_server", fields, tags) +} + +func (r *RavenDB) gatherDatabases(acc telegraf.Accumulator) { + databasesResponse := &databasesMetricResponse{} + + err := r.requestJSON(r.requestUrlDatabases, &databasesResponse) + if err != nil { + acc.AddError(err) + return + } + + for _, dbResponse := range databasesResponse.Results { + tags := map[string]string{ + "database_id": dbResponse.DatabaseId, + "database_name": dbResponse.DatabaseName, + "node_tag": databasesResponse.NodeTag, + "url": r.URL, + } + + if databasesResponse.PublicServerUrl != nil { + tags["public_server_url"] = *databasesResponse.PublicServerUrl + } + + fields := map[string]interface{}{ + "counts_alerts": dbResponse.Counts.Alerts, + "counts_attachments": dbResponse.Counts.Attachments, + "counts_documents": dbResponse.Counts.Documents, + "counts_performance_hints": dbResponse.Counts.PerformanceHints, + "counts_rehabs": dbResponse.Counts.Rehabs, + "counts_replication_factor": dbResponse.Counts.ReplicationFactor, + "counts_revisions": dbResponse.Counts.Revisions, + "counts_unique_attachments": dbResponse.Counts.UniqueAttachments, + "indexes_auto_count": dbResponse.Indexes.AutoCount, + "indexes_count": dbResponse.Indexes.Count, + "indexes_errored_count": dbResponse.Indexes.ErroredCount, + "indexes_errors_count": dbResponse.Indexes.ErrorsCount, + "indexes_disabled_count": dbResponse.Indexes.DisabledCount, + "indexes_idle_count": dbResponse.Indexes.IdleCount, + "indexes_stale_count": dbResponse.Indexes.StaleCount, + "indexes_static_count": dbResponse.Indexes.StaticCount, + "statistics_doc_puts_per_sec": dbResponse.Statistics.DocPutsPerSec, + "statistics_map_index_indexes_per_sec": dbResponse.Statistics.MapIndexIndexesPerSec, + "statistics_map_reduce_index_mapped_per_sec": dbResponse.Statistics.MapReduceIndexMappedPerSec, + "statistics_map_reduce_index_reduced_per_sec": dbResponse.Statistics.MapReduceIndexReducedPerSec, + "statistics_request_average_duration_in_ms": dbResponse.Statistics.RequestAverageDurationInMs, + "statistics_requests_count": dbResponse.Statistics.RequestsCount, + "statistics_requests_per_sec": dbResponse.Statistics.RequestsPerSec, + "storage_documents_allocated_data_file_in_mb": dbResponse.Storage.DocumentsAllocatedDataFileInMb, + "storage_documents_used_data_file_in_mb": dbResponse.Storage.DocumentsUsedDataFileInMb, + "storage_indexes_allocated_data_file_in_mb": dbResponse.Storage.IndexesAllocatedDataFileInMb, + "storage_indexes_used_data_file_in_mb": dbResponse.Storage.IndexesUsedDataFileInMb, + "storage_total_allocated_storage_file_in_mb": dbResponse.Storage.TotalAllocatedStorageFileInMb, + "storage_total_free_space_in_mb": dbResponse.Storage.TotalFreeSpaceInMb, + "time_since_last_backup_in_sec": dbResponse.TimeSinceLastBackupInSec, + "uptime_in_sec": dbResponse.UptimeInSec, + } + + acc.AddFields("ravendb_databases", fields, tags) + } +} + +func (r *RavenDB) gatherIndexes(acc telegraf.Accumulator) { + indexesResponse := &indexesMetricResponse{} + + err := r.requestJSON(r.requestUrlIndexes, &indexesResponse) + if err != nil { + acc.AddError(err) + return + } + + for _, perDbIndexResponse := range indexesResponse.Results { + for _, indexResponse := range perDbIndexResponse.Indexes { + tags := map[string]string{ + "database_name": perDbIndexResponse.DatabaseName, + "index_name": indexResponse.IndexName, + "node_tag": indexesResponse.NodeTag, + "url": r.URL, + } + + if indexesResponse.PublicServerUrl != nil { + tags["public_server_url"] = *indexesResponse.PublicServerUrl + } + + fields := map[string]interface{}{ + "errors": indexResponse.Errors, + "is_invalid": indexResponse.IsInvalid, + "lock_mode": indexResponse.LockMode, + "mapped_per_sec": indexResponse.MappedPerSec, + "priority": indexResponse.Priority, + "reduced_per_sec": indexResponse.ReducedPerSec, + "state": indexResponse.State, + "status": indexResponse.Status, + "time_since_last_indexing_in_sec": indexResponse.TimeSinceLastIndexingInSec, + "time_since_last_query_in_sec": indexResponse.TimeSinceLastQueryInSec, + "type": indexResponse.Type, + } + + acc.AddFields("ravendb_indexes", fields, tags) + } + } +} + +func (r *RavenDB) gatherCollections(acc telegraf.Accumulator) { + collectionsResponse := &collectionsMetricResponse{} + + err := r.requestJSON(r.requestUrlCollection, &collectionsResponse) + if err != nil { + acc.AddError(err) + return + } + + for _, perDbCollectionMetrics := range collectionsResponse.Results { + for _, collectionMetrics := range perDbCollectionMetrics.Collections { + tags := map[string]string{ + "collection_name": collectionMetrics.CollectionName, + "database_name": perDbCollectionMetrics.DatabaseName, + "node_tag": collectionsResponse.NodeTag, + "url": r.URL, + } + + if collectionsResponse.PublicServerUrl != nil { + tags["public_server_url"] = *collectionsResponse.PublicServerUrl + } + + fields := map[string]interface{}{ + "documents_count": collectionMetrics.DocumentsCount, + "documents_size_in_bytes": collectionMetrics.DocumentsSizeInBytes, + "revisions_size_in_bytes": collectionMetrics.RevisionsSizeInBytes, + "tombstones_size_in_bytes": collectionMetrics.TombstonesSizeInBytes, + "total_size_in_bytes": collectionMetrics.TotalSizeInBytes, + } + + acc.AddFields("ravendb_collections", fields, tags) + } + } +} + +func prepareDbNamesUrlPart(dbNames []string) string { + if len(dbNames) == 0 { + return "" + } + result := "?" + dbNames[0] + for _, db := range dbNames[1:] { + result += "&name=" + url.QueryEscape(db) + } + + return result +} + +func (r *RavenDB) Init() error { + if r.URL == "" { + r.URL = defaultURL + } + + r.requestUrlServer = r.URL + "/admin/monitoring/v1/server" + r.requestUrlDatabases = r.URL + "/admin/monitoring/v1/databases" + prepareDbNamesUrlPart(r.DbStatsDbs) + r.requestUrlIndexes = r.URL + "/admin/monitoring/v1/indexes" + prepareDbNamesUrlPart(r.IndexStatsDbs) + r.requestUrlCollection = r.URL + "/admin/monitoring/v1/collections" + prepareDbNamesUrlPart(r.IndexStatsDbs) + + err := choice.CheckSlice(r.StatsInclude, []string{"server", "databases", "indexes", "collections"}) + if err != nil { + return err + } + + err = r.ensureClient() + if nil != err { + r.Log.Errorf("Error with Client %s", err) + return err + } + + return nil +} + +func init() { + inputs.Add("ravendb", func() telegraf.Input { + return &RavenDB{ + Timeout: internal.Duration{Duration: defaultTimeout * time.Second}, + StatsInclude: []string{"server", "databases", "indexes", "collections"}, + } + }) +} diff --git a/plugins/inputs/ravendb/ravendb_dto.go b/plugins/inputs/ravendb/ravendb_dto.go new file mode 100644 index 000000000..af4012f8c --- /dev/null +++ b/plugins/inputs/ravendb/ravendb_dto.go @@ -0,0 +1,199 @@ +package ravendb + +type serverMetricsResponse struct { + ServerVersion string `json:"ServerVersion"` + ServerFullVersion string `json:"ServerFullVersion"` + UpTimeInSec int32 `json:"UpTimeInSec"` + ServerProcessId int32 `json:"ServerProcessId"` + Backup backupMetrics `json:"Backup"` + Config configurationMetrics `json:"Config"` + Cpu cpuMetrics `json:"Cpu"` + Memory memoryMetrics `json:"Memory"` + Disk diskMetrics `json:"Disk"` + License licenseMetrics `json:"License"` + Network networkMetrics `json:"Network"` + Certificate certificateMetrics `json:"Certificate"` + Cluster clusterMetrics `json:"Cluster"` + Databases allDatabasesMetrics `json:"Databases"` +} + +type backupMetrics struct { + CurrentNumberOfRunningBackups int32 `json:"CurrentNumberOfRunningBackups"` + MaxNumberOfConcurrentBackups int32 `json:"MaxNumberOfConcurrentBackups"` +} + +type configurationMetrics struct { + ServerUrls []string `json:"ServerUrls"` + PublicServerUrl *string `json:"PublicServerUrl"` + TcpServerUrls []string `json:"TcpServerUrls"` + PublicTcpServerUrls []string `json:"PublicTcpServerUrls"` +} + +type cpuMetrics struct { + ProcessUsage float64 `json:"ProcessUsage"` + MachineUsage float64 `json:"MachineUsage"` + MachineIoWait *float64 `json:"MachineIoWait"` + ProcessorCount int32 `json:"ProcessorCount"` + AssignedProcessorCount int32 `json:"AssignedProcessorCount"` + ThreadPoolAvailableWorkerThreads int32 `json:"ThreadPoolAvailableWorkerThreads"` + ThreadPoolAvailableCompletionPortThreads int32 `json:"ThreadPoolAvailableCompletionPortThreads"` +} + +type memoryMetrics struct { + AllocatedMemoryInMb int64 `json:"AllocatedMemoryInMb"` + PhysicalMemoryInMb int64 `json:"PhysicalMemoryInMb"` + InstalledMemoryInMb int64 `json:"InstalledMemoryInMb"` + LowMemorySeverity string `json:"LowMemorySeverity"` + TotalSwapSizeInMb int64 `json:"TotalSwapSizeInMb"` + TotalSwapUsageInMb int64 `json:"TotalSwapUsageInMb"` + WorkingSetSwapUsageInMb int64 `json:"WorkingSetSwapUsageInMb"` + TotalDirtyInMb int64 `json:"TotalDirtyInMb"` +} + +type diskMetrics struct { + SystemStoreUsedDataFileSizeInMb int64 `json:"SystemStoreUsedDataFileSizeInMb"` + SystemStoreTotalDataFileSizeInMb int64 `json:"SystemStoreTotalDataFileSizeInMb"` + TotalFreeSpaceInMb int64 `json:"TotalFreeSpaceInMb"` + RemainingStorageSpacePercentage int64 `json:"RemainingStorageSpacePercentage"` +} + +type licenseMetrics struct { + Type string `json:"Type"` + ExpirationLeftInSec *float64 `json:"ExpirationLeftInSec"` + UtilizedCpuCores int32 `json:"UtilizedCpuCores"` + MaxCores int32 `json:"MaxCores"` +} + +type networkMetrics struct { + TcpActiveConnections int64 `json:"TcpActiveConnections"` + ConcurrentRequestsCount int64 `json:"ConcurrentRequestsCount"` + TotalRequests int64 `json:"TotalRequests"` + RequestsPerSec float64 `json:"RequestsPerSec"` + LastRequestTimeInSec *float64 `json:"LastRequestTimeInSec"` + LastAuthorizedNonClusterAdminRequestTimeInSec *float64 `json:"LastAuthorizedNonClusterAdminRequestTimeInSec"` +} + +type certificateMetrics struct { + ServerCertificateExpirationLeftInSec *float64 `json:"ServerCertificateExpirationLeftInSec"` + WellKnownAdminCertificates []string `json:"WellKnownAdminCertificates"` +} + +type clusterMetrics struct { + NodeTag string `json:"NodeTag"` + NodeState string `json:"NodeState"` + CurrentTerm int64 `json:"CurrentTerm"` + Index int64 `json:"Index"` + Id string `json:"Id"` +} + +type allDatabasesMetrics struct { + TotalCount int32 `json:"TotalCount"` + LoadedCount int32 `json:"LoadedCount"` +} + +type databasesMetricResponse struct { + Results []*databaseMetrics `json:"Results"` + PublicServerUrl *string `json:"PublicServerUrl"` + NodeTag string `json:"NodeTag"` +} + +type databaseMetrics struct { + DatabaseName string `json:"DatabaseName"` + DatabaseId string `json:"DatabaseId"` + UptimeInSec float64 `json:"UptimeInSec"` + TimeSinceLastBackupInSec *float64 `json:"TimeSinceLastBackupInSec"` + + Counts databaseCounts `json:"Counts"` + Statistics databaseStatistics `json:"Statistics"` + + Indexes databaseIndexesMetrics `json:"Indexes"` + Storage databaseStorageMetrics `json:"Storage"` +} + +type databaseCounts struct { + Documents int64 `json:"Documents"` + Revisions int64 `json:"Revisions"` + Attachments int64 `json:"Attachments"` + UniqueAttachments int64 `json:"UniqueAttachments"` + Alerts int64 `json:"Alerts"` + Rehabs int32 `json:"Rehabs"` + PerformanceHints int64 `json:"PerformanceHints"` + ReplicationFactor int32 `json:"ReplicationFactor"` +} + +type databaseStatistics struct { + DocPutsPerSec float64 `json:"DocPutsPerSec"` + MapIndexIndexesPerSec float64 `json:"MapIndexIndexesPerSec"` + MapReduceIndexMappedPerSec float64 `json:"MapReduceIndexMappedPerSec"` + MapReduceIndexReducedPerSec float64 `json:"MapReduceIndexReducedPerSec"` + RequestsPerSec float64 `json:"RequestsPerSec"` + RequestsCount int32 `json:"RequestsCount"` + RequestAverageDurationInMs float64 `json:"RequestAverageDurationInMs"` +} + +type databaseIndexesMetrics struct { + Count int64 `json:"Count"` + StaleCount int32 `json:"StaleCount"` + ErrorsCount int64 `json:"ErrorsCount"` + StaticCount int32 `json:"StaticCount"` + AutoCount int32 `json:"AutoCount"` + IdleCount int32 `json:"IdleCount"` + DisabledCount int32 `json:"DisabledCount"` + ErroredCount int32 `json:"ErroredCount"` +} + +type databaseStorageMetrics struct { + DocumentsAllocatedDataFileInMb int64 `json:"DocumentsAllocatedDataFileInMb"` + DocumentsUsedDataFileInMb int64 `json:"DocumentsUsedDataFileInMb"` + IndexesAllocatedDataFileInMb int64 `json:"IndexesAllocatedDataFileInMb"` + IndexesUsedDataFileInMb int64 `json:"IndexesUsedDataFileInMb"` + TotalAllocatedStorageFileInMb int64 `json:"TotalAllocatedStorageFileInMb"` + TotalFreeSpaceInMb int64 `json:"TotalFreeSpaceInMb"` +} + +type indexesMetricResponse struct { + Results []*perDatabaseIndexMetrics `json:"Results"` + PublicServerUrl *string `json:"PublicServerUrl"` + NodeTag string `json:"NodeTag"` +} + +type perDatabaseIndexMetrics struct { + DatabaseName string `json:"DatabaseName"` + Indexes []*indexMetrics `json:"Indexes"` +} + +type indexMetrics struct { + IndexName string `json:"IndexName"` + Priority string `json:"Priority"` + State string `json:"State"` + Errors int32 `json:"Errors"` + TimeSinceLastQueryInSec *float64 `json:"TimeSinceLastQueryInSec"` + TimeSinceLastIndexingInSec *float64 `json:"TimeSinceLastIndexingInSec"` + LockMode string `json:"LockMode"` + IsInvalid bool `json:"IsInvalid"` + Status string `json:"Status"` + MappedPerSec float64 `json:"MappedPerSec"` + ReducedPerSec float64 `json:"ReducedPerSec"` + Type string `json:"Type"` + EntriesCount int32 `json:"EntriesCount"` +} + +type collectionsMetricResponse struct { + Results []*perDatabaseCollectionMetrics `json:"Results"` + PublicServerUrl *string `json:"PublicServerUrl"` + NodeTag string `json:"NodeTag"` +} + +type perDatabaseCollectionMetrics struct { + DatabaseName string `json:"DatabaseName"` + Collections []*collectionMetrics `json:"Collections"` +} + +type collectionMetrics struct { + CollectionName string `json:"CollectionName"` + DocumentsCount int64 `json:"DocumentsCount"` + TotalSizeInBytes int64 `json:"TotalSizeInBytes"` + DocumentsSizeInBytes int64 `json:"DocumentsSizeInBytes"` + TombstonesSizeInBytes int64 `json:"TombstonesSizeInBytes"` + RevisionsSizeInBytes int64 `json:"RevisionsSizeInBytes"` +} diff --git a/plugins/inputs/ravendb/ravendb_test.go b/plugins/inputs/ravendb/ravendb_test.go new file mode 100644 index 000000000..754ece88f --- /dev/null +++ b/plugins/inputs/ravendb/ravendb_test.go @@ -0,0 +1,393 @@ +package ravendb + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/influxdata/telegraf/testutil" + "github.com/stretchr/testify/require" +) + +// Test against fully filled data +func TestRavenDBGeneratesMetricsFull(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var jsonFilePath string + + switch r.URL.Path { + case "/admin/monitoring/v1/databases": + jsonFilePath = "testdata/databases_full.json" + case "/admin/monitoring/v1/server": + jsonFilePath = "testdata/server_full.json" + case "/admin/monitoring/v1/indexes": + jsonFilePath = "testdata/indexes_full.json" + case "/admin/monitoring/v1/collections": + jsonFilePath = "testdata/collections_full.json" + + default: + panic(fmt.Sprintf("Cannot handle request for uri %s", r.URL.Path)) + } + + data, err := ioutil.ReadFile(jsonFilePath) + + if err != nil { + panic(fmt.Sprintf("could not read from data file %s", jsonFilePath)) + } + + w.Write(data) + })) + defer ts.Close() + + r := &RavenDB{ + URL: ts.URL, + StatsInclude: []string{"server", "databases", "indexes", "collections"}, + Log: testutil.Logger{}, + } + + r.Init() + + acc := &testutil.Accumulator{} + + err := acc.GatherError(r.Gather) + require.NoError(t, err) + + serverFields := map[string]interface{}{ + "server_version": "5.1", + "server_full_version": "5.1.1-custom-51", + "uptime_in_sec": int64(30), + "server_process_id": 26360, + "config_server_urls": "http://127.0.0.1:8080;http://192.168.0.1:8080", + "config_tcp_server_urls": "tcp://127.0.0.1:3888;tcp://192.168.0.1:3888", + "config_public_tcp_server_urls": "tcp://2.3.4.5:3888;tcp://6.7.8.9:3888", + "backup_max_number_of_concurrent_backups": 4, + "backup_current_number_of_running_backups": 2, + "cpu_process_usage": 6.28, + "cpu_machine_usage": 41.05, + "cpu_machine_io_wait": 2.55, + "cpu_processor_count": 8, + "cpu_assigned_processor_count": 7, + "cpu_thread_pool_available_worker_threads": 32766, + "cpu_thread_pool_available_completion_port_threads": 1000, + "memory_allocated_in_mb": 235, + "memory_installed_in_mb": 16384, + "memory_physical_in_mb": 16250, + "memory_low_memory_severity": "None", + "memory_total_swap_size_in_mb": 1024, + "memory_total_swap_usage_in_mb": 456, + "memory_working_set_swap_usage_in_mb": 89, + "memory_total_dirty_in_mb": 1, + "disk_system_store_used_data_file_size_in_mb": 28, + "disk_system_store_total_data_file_size_in_mb": 32, + "disk_total_free_space_in_mb": 52078, + "disk_remaining_storage_space_percentage": 22, + "license_type": "Enterprise", + "license_expiration_left_in_sec": 25466947.5, + "license_utilized_cpu_cores": 8, + "license_max_cores": 256, + "network_tcp_active_connections": 84, + "network_concurrent_requests_count": 1, + "network_total_requests": 3, + "network_requests_per_sec": 0.03322, + "network_last_request_time_in_sec": 0.0264977, + "network_last_authorized_non_cluster_admin_request_time_in_sec": 0.04, + "certificate_server_certificate_expiration_left_in_sec": float64(104), + "certificate_well_known_admin_certificates": "a909502dd82ae41433e6f83886b00d4277a32a7b;4444444444444444444444444444444444444444", + "cluster_node_state": "Leader", + "cluster_current_term": 28, + "cluster_index": 104, + "databases_total_count": 25, + "databases_loaded_count": 2, + } + + serverTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "cluster_id": "6b535a18-558f-4e53-a479-a514efc16aab", + "public_server_url": "http://raven1:8080", + } + + defaultTime := time.Unix(0, 0) + + dbFields := map[string]interface{}{ + "uptime_in_sec": float64(1396), + "time_since_last_backup_in_sec": 104.3, + "counts_documents": 425189, + "counts_revisions": 429605, + "counts_attachments": 17, + "counts_unique_attachments": 16, + "counts_alerts": 2, + "counts_rehabs": 3, + "counts_performance_hints": 5, + "counts_replication_factor": 2, + "statistics_doc_puts_per_sec": 23.4, + "statistics_map_index_indexes_per_sec": 82.5, + "statistics_map_reduce_index_mapped_per_sec": 50.3, + "statistics_map_reduce_index_reduced_per_sec": 85.2, + "statistics_requests_per_sec": 22.5, + "statistics_requests_count": 809, + "statistics_request_average_duration_in_ms": 0.55, + "indexes_count": 7, + "indexes_stale_count": 1, + "indexes_errors_count": 2, + "indexes_static_count": 7, + "indexes_auto_count": 3, + "indexes_idle_count": 4, + "indexes_disabled_count": 5, + "indexes_errored_count": 6, + "storage_documents_allocated_data_file_in_mb": 1024, + "storage_documents_used_data_file_in_mb": 942, + "storage_indexes_allocated_data_file_in_mb": 464, + "storage_indexes_used_data_file_in_mb": 278, + "storage_total_allocated_storage_file_in_mb": 1496, + "storage_total_free_space_in_mb": 52074, + } + + dbTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "database_name": "db2", + "database_id": "06eefe8b-d720-4a8d-a809-2c5af9a4abb5", + "public_server_url": "http://myhost:8080", + } + + indexFields := map[string]interface{}{ + "priority": "Normal", + "state": "Normal", + "errors": 0, + "time_since_last_query_in_sec": 3.4712567, + "time_since_last_indexing_in_sec": 3.4642612, + "lock_mode": "Unlock", + "is_invalid": true, + "status": "Running", + "mapped_per_sec": 102.34, + "reduced_per_sec": 593.23, + "type": "MapReduce", + } + + indexTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "public_server_url": "http://localhost:8080", + "database_name": "db1", + "index_name": "Product/Rating", + } + + collectionFields := map[string]interface{}{ + "documents_count": 830, + "total_size_in_bytes": 2744320, + "documents_size_in_bytes": 868352, + "tombstones_size_in_bytes": 122880, + "revisions_size_in_bytes": 1753088, + } + + collectionTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "database_name": "db1", + "collection_name": "Orders", + "public_server_url": "http://localhost:8080", + } + + serverExpected := testutil.MustMetric("ravendb_server", serverTags, serverFields, defaultTime) + dbExpected := testutil.MustMetric("ravendb_databases", dbTags, dbFields, defaultTime) + indexExpected := testutil.MustMetric("ravendb_indexes", indexTags, indexFields, defaultTime) + collectionsExpected := testutil.MustMetric("ravendb_collections", collectionTags, collectionFields, defaultTime) + + for _, metric := range acc.GetTelegrafMetrics() { + switch metric.Name() { + case "ravendb_server": + testutil.RequireMetricEqual(t, serverExpected, metric, testutil.IgnoreTime()) + case "ravendb_databases": + testutil.RequireMetricEqual(t, dbExpected, metric, testutil.IgnoreTime()) + case "ravendb_indexes": + testutil.RequireMetricEqual(t, indexExpected, metric, testutil.IgnoreTime()) + case "ravendb_collections": + testutil.RequireMetricEqual(t, collectionsExpected, metric, testutil.IgnoreTime()) + } + } +} + +// Test against minimum filled data +func TestRavenDBGeneratesMetricsMin(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var jsonFilePath string + + switch r.URL.Path { + case "/admin/monitoring/v1/databases": + jsonFilePath = "testdata/databases_min.json" + case "/admin/monitoring/v1/server": + jsonFilePath = "testdata/server_min.json" + case "/admin/monitoring/v1/indexes": + jsonFilePath = "testdata/indexes_min.json" + case "/admin/monitoring/v1/collections": + jsonFilePath = "testdata/collections_min.json" + default: + panic(fmt.Sprintf("Cannot handle request for uri %s", r.URL.Path)) + } + + data, err := ioutil.ReadFile(jsonFilePath) + + if err != nil { + panic(fmt.Sprintf("could not read from data file %s", jsonFilePath)) + } + + w.Write(data) + })) + defer ts.Close() + + r := &RavenDB{ + URL: ts.URL, + StatsInclude: []string{"server", "databases", "indexes", "collections"}, + Log: testutil.Logger{}, + } + + r.Init() + + acc := &testutil.Accumulator{} + + err := acc.GatherError(r.Gather) + require.NoError(t, err) + + serverFields := map[string]interface{}{ + "server_version": "5.1", + "server_full_version": "5.1.1-custom-51", + "uptime_in_sec": 30, + "server_process_id": 26360, + "config_server_urls": "http://127.0.0.1:8080", + "backup_max_number_of_concurrent_backups": 4, + "backup_current_number_of_running_backups": 2, + "cpu_process_usage": 6.28, + "cpu_machine_usage": 41.07, + "cpu_processor_count": 8, + "cpu_assigned_processor_count": 7, + "cpu_thread_pool_available_worker_threads": 32766, + "cpu_thread_pool_available_completion_port_threads": 1000, + "memory_allocated_in_mb": 235, + "memory_installed_in_mb": 16384, + "memory_physical_in_mb": 16250, + "memory_low_memory_severity": "Low", + "memory_total_swap_size_in_mb": 1024, + "memory_total_swap_usage_in_mb": 456, + "memory_working_set_swap_usage_in_mb": 89, + "memory_total_dirty_in_mb": 1, + "disk_system_store_used_data_file_size_in_mb": 28, + "disk_system_store_total_data_file_size_in_mb": 32, + "disk_total_free_space_in_mb": 52078, + "disk_remaining_storage_space_percentage": 22, + "license_type": "Enterprise", + "license_utilized_cpu_cores": 8, + "license_max_cores": 256, + "network_tcp_active_connections": 84, + "network_concurrent_requests_count": 1, + "network_total_requests": 3, + "network_requests_per_sec": 0.03322, + "cluster_node_state": "Leader", + "cluster_current_term": 28, + "cluster_index": 104, + "databases_total_count": 25, + "databases_loaded_count": 2, + } + + serverTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "cluster_id": "6b535a18-558f-4e53-a479-a514efc16aab", + } + + dbFields := map[string]interface{}{ + "uptime_in_sec": float64(1396), + "counts_documents": 425189, + "counts_revisions": 429605, + "counts_attachments": 17, + "counts_unique_attachments": 16, + "counts_alerts": 2, + "counts_rehabs": 3, + "counts_performance_hints": 5, + "counts_replication_factor": 2, + "statistics_doc_puts_per_sec": 23.4, + "statistics_map_index_indexes_per_sec": 82.5, + "statistics_map_reduce_index_mapped_per_sec": 50.3, + "statistics_map_reduce_index_reduced_per_sec": 85.2, + "statistics_requests_per_sec": 22.5, + "statistics_requests_count": 809, + "statistics_request_average_duration_in_ms": 0.55, + "indexes_count": 7, + "indexes_stale_count": 1, + "indexes_errors_count": 2, + "indexes_static_count": 7, + "indexes_auto_count": 3, + "indexes_idle_count": 4, + "indexes_disabled_count": 5, + "indexes_errored_count": 6, + "storage_documents_allocated_data_file_in_mb": 1024, + "storage_documents_used_data_file_in_mb": 942, + "storage_indexes_allocated_data_file_in_mb": 464, + "storage_indexes_used_data_file_in_mb": 278, + "storage_total_allocated_storage_file_in_mb": 1496, + "storage_total_free_space_in_mb": 52074, + } + + dbTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "database_name": "db2", + "database_id": "06eefe8b-d720-4a8d-a809-2c5af9a4abb5", + } + + indexFields := map[string]interface{}{ + "priority": "Normal", + "state": "Normal", + "errors": 0, + "lock_mode": "Unlock", + "is_invalid": false, + "status": "Running", + "mapped_per_sec": 102.34, + "reduced_per_sec": 593.23, + "type": "MapReduce", + } + + indexTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "database_name": "db1", + "index_name": "Product/Rating", + } + + collectionFields := map[string]interface{}{ + "documents_count": 830, + "total_size_in_bytes": 2744320, + "documents_size_in_bytes": 868352, + "tombstones_size_in_bytes": 122880, + "revisions_size_in_bytes": 1753088, + } + + collectionTags := map[string]string{ + "url": ts.URL, + "node_tag": "A", + "database_name": "db1", + "collection_name": "Orders", + } + + defaultTime := time.Unix(0, 0) + + serverExpected := testutil.MustMetric("ravendb_server", serverTags, serverFields, defaultTime) + dbExpected := testutil.MustMetric("ravendb_databases", dbTags, dbFields, defaultTime) + indexExpected := testutil.MustMetric("ravendb_indexes", indexTags, indexFields, defaultTime) + collectionsExpected := testutil.MustMetric("ravendb_collections", collectionTags, collectionFields, defaultTime) + + for _, metric := range acc.GetTelegrafMetrics() { + switch metric.Name() { + case "ravendb_server": + testutil.RequireMetricEqual(t, serverExpected, metric, testutil.IgnoreTime()) + case "ravendb_databases": + testutil.RequireMetricEqual(t, dbExpected, metric, testutil.IgnoreTime()) + case "ravendb_indexes": + testutil.RequireMetricEqual(t, indexExpected, metric, testutil.IgnoreTime()) + case "ravendb_collections": + testutil.RequireMetricEqual(t, collectionsExpected, metric, testutil.IgnoreTime()) + } + } +} diff --git a/plugins/inputs/ravendb/testdata/collections_full.json b/plugins/inputs/ravendb/testdata/collections_full.json new file mode 100644 index 000000000..db91e9086 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/collections_full.json @@ -0,0 +1,19 @@ +{ + "PublicServerUrl": "http://localhost:8080", + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db1", + "Collections": [ + { + "CollectionName": "Orders", + "DocumentsCount": 830, + "TotalSizeInBytes": 2744320, + "DocumentsSizeInBytes": 868352, + "TombstonesSizeInBytes": 122880, + "RevisionsSizeInBytes": 1753088 + } + ] + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/collections_min.json b/plugins/inputs/ravendb/testdata/collections_min.json new file mode 100644 index 000000000..edd636d21 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/collections_min.json @@ -0,0 +1,19 @@ +{ + "PublicServerUrl": null, + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db1", + "Collections": [ + { + "CollectionName": "Orders", + "DocumentsCount": 830, + "TotalSizeInBytes": 2744320, + "DocumentsSizeInBytes": 868352, + "TombstonesSizeInBytes": 122880, + "RevisionsSizeInBytes": 1753088 + } + ] + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/databases_full.json b/plugins/inputs/ravendb/testdata/databases_full.json new file mode 100644 index 000000000..1c7456881 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/databases_full.json @@ -0,0 +1,49 @@ +{ + "PublicServerUrl": "http://myhost:8080", + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db2", + "DatabaseId": "06eefe8b-d720-4a8d-a809-2c5af9a4abb5", + "UptimeInSec": 1396, + "TimeSinceLastBackupInSec": 104.3, + "Counts": { + "Documents": 425189, + "Revisions": 429605, + "Attachments": 17, + "UniqueAttachments": 16, + "Alerts": 2, + "Rehabs": 3, + "PerformanceHints": 5, + "ReplicationFactor": 2 + }, + "Statistics": { + "DocPutsPerSec": 23.4, + "MapIndexIndexesPerSec": 82.5, + "MapReduceIndexMappedPerSec": 50.3, + "MapReduceIndexReducedPerSec": 85.2, + "RequestsPerSec": 22.5, + "RequestsCount": 809, + "RequestAverageDurationInMs": 0.55 + }, + "Indexes": { + "Count": 7, + "StaleCount": 1, + "ErrorsCount": 2, + "StaticCount": 7, + "AutoCount": 3, + "IdleCount": 4, + "DisabledCount": 5, + "ErroredCount": 6 + }, + "Storage": { + "DocumentsAllocatedDataFileInMb": 1024, + "DocumentsUsedDataFileInMb": 942, + "IndexesAllocatedDataFileInMb": 464, + "IndexesUsedDataFileInMb": 278, + "TotalAllocatedStorageFileInMb": 1496, + "TotalFreeSpaceInMb": 52074 + } + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/databases_min.json b/plugins/inputs/ravendb/testdata/databases_min.json new file mode 100644 index 000000000..48a1ccbb6 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/databases_min.json @@ -0,0 +1,49 @@ +{ + "PublicServerUrl": null, + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db2", + "DatabaseId": "06eefe8b-d720-4a8d-a809-2c5af9a4abb5", + "UptimeInSec": 1396, + "TimeSinceLastBackupInSec": null, + "Counts": { + "Documents": 425189, + "Revisions": 429605, + "Attachments": 17, + "UniqueAttachments": 16, + "Alerts": 2, + "Rehabs": 3, + "PerformanceHints": 5, + "ReplicationFactor": 2 + }, + "Statistics": { + "DocPutsPerSec": 23.4, + "MapIndexIndexesPerSec": 82.5, + "MapReduceIndexMappedPerSec": 50.3, + "MapReduceIndexReducedPerSec": 85.2, + "RequestsPerSec": 22.5, + "RequestsCount": 809, + "RequestAverageDurationInMs": 0.55 + }, + "Indexes": { + "Count": 7, + "StaleCount": 1, + "ErrorsCount": 2, + "StaticCount": 7, + "AutoCount": 3, + "IdleCount": 4, + "DisabledCount": 5, + "ErroredCount": 6 + }, + "Storage": { + "DocumentsAllocatedDataFileInMb": 1024, + "DocumentsUsedDataFileInMb": 942, + "IndexesAllocatedDataFileInMb": 464, + "IndexesUsedDataFileInMb": 278, + "TotalAllocatedStorageFileInMb": 1496, + "TotalFreeSpaceInMb": 52074 + } + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/indexes_full.json b/plugins/inputs/ravendb/testdata/indexes_full.json new file mode 100644 index 000000000..d67ded7d1 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/indexes_full.json @@ -0,0 +1,25 @@ +{ + "PublicServerUrl": "http://localhost:8080", + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db1", + "Indexes": [ + { + "IndexName": "Product/Rating", + "Priority": "Normal", + "State": "Normal", + "Errors": 0, + "TimeSinceLastQueryInSec": 3.4712567, + "TimeSinceLastIndexingInSec": 3.4642612, + "LockMode": "Unlock", + "IsInvalid": true, + "Status": "Running", + "MappedPerSec": 102.34, + "ReducedPerSec": 593.23, + "Type": "MapReduce" + } + ] + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/indexes_min.json b/plugins/inputs/ravendb/testdata/indexes_min.json new file mode 100644 index 000000000..493bda8b7 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/indexes_min.json @@ -0,0 +1,25 @@ +{ + "PublicServerUrl": null, + "NodeTag": "A", + "Results": [ + { + "DatabaseName": "db1", + "Indexes": [ + { + "IndexName": "Product/Rating", + "Priority": "Normal", + "State": "Normal", + "Errors": 0, + "TimeSinceLastQueryInSec": null, + "TimeSinceLastIndexingInSec": null, + "LockMode": "Unlock", + "IsInvalid": false, + "Status": "Running", + "MappedPerSec": 102.34, + "ReducedPerSec": 593.23, + "Type": "MapReduce" + } + ] + } + ] +} diff --git a/plugins/inputs/ravendb/testdata/server_full.json b/plugins/inputs/ravendb/testdata/server_full.json new file mode 100644 index 000000000..edfbbbf79 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/server_full.json @@ -0,0 +1,73 @@ +{ + "ServerVersion": "5.1", + "ServerFullVersion": "5.1.1-custom-51", + "UpTimeInSec": 30, + "ServerProcessId": 26360, + "Config": { + "ServerUrls": [ + "http://127.0.0.1:8080", + "http://192.168.0.1:8080" + ], + "PublicServerUrl": "http://raven1:8080", + "TcpServerUrls": ["tcp://127.0.0.1:3888", "tcp://192.168.0.1:3888"], + "PublicTcpServerUrls": ["tcp://2.3.4.5:3888", "tcp://6.7.8.9:3888"] + }, + "Backup": { + "CurrentNumberOfRunningBackups": 2, + "MaxNumberOfConcurrentBackups": 4 + }, + "Cpu": { + "ProcessUsage": 6.28, + "MachineUsage": 41.05, + "MachineIoWait": 2.55, + "ProcessorCount": 8, + "AssignedProcessorCount": 7, + "ThreadPoolAvailableWorkerThreads": 32766, + "ThreadPoolAvailableCompletionPortThreads": 1000 + }, + "Memory": { + "AllocatedMemoryInMb": 235, + "PhysicalMemoryInMb": 16250, + "InstalledMemoryInMb": 16384, + "LowMemorySeverity": "None", + "TotalSwapSizeInMb": 1024, + "TotalSwapUsageInMb": 456, + "WorkingSetSwapUsageInMb": 89, + "TotalDirtyInMb": 1 + }, + "Disk": { + "SystemStoreUsedDataFileSizeInMb": 28, + "SystemStoreTotalDataFileSizeInMb": 32, + "TotalFreeSpaceInMb": 52078, + "RemainingStorageSpacePercentage": 22 + }, + "License": { + "Type": "Enterprise", + "ExpirationLeftInSec": 25466947.5, + "UtilizedCpuCores": 8, + "MaxCores": 256 + }, + "Network": { + "TcpActiveConnections": 84, + "ConcurrentRequestsCount": 1, + "TotalRequests": 3, + "RequestsPerSec": 0.03322, + "LastRequestTimeInSec": 0.0264977, + "LastAuthorizedNonClusterAdminRequestTimeInSec": 0.04 + }, + "Certificate": { + "ServerCertificateExpirationLeftInSec": 104, + "WellKnownAdminCertificates": ["a909502dd82ae41433e6f83886b00d4277a32a7b", "4444444444444444444444444444444444444444"] + }, + "Cluster": { + "NodeTag": "A", + "NodeState": "Leader", + "CurrentTerm": 28, + "Index": 104, + "Id": "6b535a18-558f-4e53-a479-a514efc16aab" + }, + "Databases": { + "TotalCount": 25, + "LoadedCount": 2 + } +} diff --git a/plugins/inputs/ravendb/testdata/server_min.json b/plugins/inputs/ravendb/testdata/server_min.json new file mode 100644 index 000000000..e22bd03d4 --- /dev/null +++ b/plugins/inputs/ravendb/testdata/server_min.json @@ -0,0 +1,72 @@ +{ + "ServerVersion": "5.1", + "ServerFullVersion": "5.1.1-custom-51", + "UpTimeInSec": 30, + "ServerProcessId": 26360, + "Config": { + "ServerUrls": [ + "http://127.0.0.1:8080" + ], + "PublicServerUrl": null, + "TcpServerUrls": null, + "PublicTcpServerUrls": null + }, + "Backup": { + "CurrentNumberOfRunningBackups": 2, + "MaxNumberOfConcurrentBackups": 4 + }, + "Cpu": { + "ProcessUsage": 6.28, + "MachineUsage": 41.07, + "MachineIoWait": null, + "ProcessorCount": 8, + "AssignedProcessorCount": 7, + "ThreadPoolAvailableWorkerThreads": 32766, + "ThreadPoolAvailableCompletionPortThreads": 1000 + }, + "Memory": { + "AllocatedMemoryInMb": 235, + "PhysicalMemoryInMb": 16250, + "InstalledMemoryInMb": 16384, + "LowMemorySeverity": "Low", + "TotalSwapSizeInMb": 1024, + "TotalSwapUsageInMb": 456, + "WorkingSetSwapUsageInMb": 89, + "TotalDirtyInMb": 1 + }, + "Disk": { + "SystemStoreUsedDataFileSizeInMb": 28, + "SystemStoreTotalDataFileSizeInMb": 32, + "TotalFreeSpaceInMb": 52078, + "RemainingStorageSpacePercentage": 22 + }, + "License": { + "Type": "Enterprise", + "ExpirationLeftInSec": null, + "UtilizedCpuCores": 8, + "MaxCores": 256 + }, + "Network": { + "TcpActiveConnections": 84, + "ConcurrentRequestsCount": 1, + "TotalRequests": 3, + "RequestsPerSec": 0.03322, + "LastRequestTimeInSec": null, + "LastAuthorizedNonClusterAdminRequestTimeInSec": null + }, + "Certificate": { + "ServerCertificateExpirationLeftInSec": null, + "WellKnownAdminCertificates": null + }, + "Cluster": { + "NodeTag": "A", + "NodeState": "Leader", + "CurrentTerm": 28, + "Index": 104, + "Id": "6b535a18-558f-4e53-a479-a514efc16aab" + }, + "Databases": { + "TotalCount": 25, + "LoadedCount": 2 + } +}