netdata/netdata

View on GitHub
src/go/collectors/go.d.plugin/modules/elasticsearch/charts.go

Summary

Maintainability
F
3 days
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package elasticsearch

import (
    "fmt"
    "strings"

    "github.com/netdata/netdata/go/go.d.plugin/agent/module"
)

const (
    prioNodeIndicesIndexingOps = module.Priority + iota
    prioNodeIndicesIndexingOpsCurrent
    prioNodeIndicesIndexingOpsTime
    prioNodeIndicesSearchOps
    prioNodeIndicesSearchOpsCurrent
    prioNodeIndicesSearchOpsTime
    prioNodeIndicesRefreshOps
    prioNodeIndicesRefreshOpsTime
    prioNodeIndicesFlushOps
    prioNodeIndicesFlushOpsTime
    prioNodeIndicesFieldDataMemoryUsage
    prioNodeIndicesFieldDataEvictions
    prioNodeIndicesSegmentsCount
    prioNodeIndicesSegmentsMemoryUsageTotal
    prioNodeIndicesSegmentsMemoryUsage
    prioNodeIndicesTransLogOps
    prioNodeIndexTransLogSize
    prioNodeFileDescriptors
    prioNodeJVMMemHeap
    prioNodeJVMMemHeapBytes
    prioNodeJVMBufferPoolsCount
    prioNodeJVMBufferPoolDirectMemory
    prioNodeJVMBufferPoolMappedMemory
    prioNodeJVMGCCount
    prioNodeJVMGCTime
    prioNodeThreadPoolQueued
    prioNodeThreadPoolRejected
    prioNodeClusterCommunicationPackets
    prioNodeClusterCommunication
    prioNodeHTTPConnections
    prioNodeBreakersTrips

    prioClusterStatus
    prioClusterNodesCount
    prioClusterShardsCount
    prioClusterPendingTasks
    prioClusterInFlightFetchesCount

    prioClusterIndicesCount
    prioClusterIndicesShardsCount
    prioClusterIndicesDocsCount
    prioClusterIndicesStoreSize
    prioClusterIndicesQueryCache
    prioClusterNodesByRoleCount

    prioNodeIndexHealth
    prioNodeIndexShardsCount
    prioNodeIndexDocsCount
    prioNodeIndexStoreSize
)

var nodeChartsTmpl = module.Charts{
    nodeIndicesIndexingOpsChartTmpl.Copy(),
    nodeIndicesIndexingOpsCurrentChartTmpl.Copy(),
    nodeIndicesIndexingOpsTimeChartTmpl.Copy(),

    nodeIndicesSearchOpsChartTmpl.Copy(),
    nodeIndicesSearchOpsCurrentChartTmpl.Copy(),
    nodeIndicesSearchOpsTimeChartTmpl.Copy(),

    nodeIndicesRefreshOpsChartTmpl.Copy(),
    nodeIndicesRefreshOpsTimeChartTmpl.Copy(),

    nodeIndicesFlushOpsChartTmpl.Copy(),
    nodeIndicesFlushOpsTimeChartTmpl.Copy(),

    nodeIndicesFieldDataMemoryUsageChartTmpl.Copy(),
    nodeIndicesFieldDataEvictionsChartTmpl.Copy(),

    nodeIndicesSegmentsCountChartTmpl.Copy(),
    nodeIndicesSegmentsMemoryUsageTotalChartTmpl.Copy(),
    nodeIndicesSegmentsMemoryUsageChartTmpl.Copy(),

    nodeIndicesTransLogOpsChartTmpl.Copy(),
    nodeIndexTransLogSizeChartTmpl.Copy(),

    nodeFileDescriptorsChartTmpl.Copy(),

    nodeJVMMemHeapChartTmpl.Copy(),
    nodeJVMMemHeapBytesChartTmpl.Copy(),
    nodeJVMBufferPoolsCountChartTmpl.Copy(),
    nodeJVMBufferPoolDirectMemoryChartTmpl.Copy(),
    nodeJVMBufferPoolMappedMemoryChartTmpl.Copy(),
    nodeJVMGCCountChartTmpl.Copy(),
    nodeJVMGCTimeChartTmpl.Copy(),

    nodeThreadPoolQueuedChartTmpl.Copy(),
    nodeThreadPoolRejectedChartTmpl.Copy(),

    nodeClusterCommunicationPacketsChartTmpl.Copy(),
    nodeClusterCommunicationChartTmpl.Copy(),

    nodeHTTPConnectionsChartTmpl.Copy(),

    nodeBreakersTripsChartTmpl.Copy(),
}

var (
    nodeIndicesIndexingOpsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_indexing_operations",
        Title:    "Indexing Operations",
        Units:    "operations/s",
        Fam:      "indices indexing",
        Ctx:      "elasticsearch.node_indices_indexing",
        Priority: prioNodeIndicesIndexingOps,
        Dims: module.Dims{
            {ID: "node_%s_indices_indexing_index_total", Name: "index", Algo: module.Incremental},
        },
    }
    nodeIndicesIndexingOpsCurrentChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_indexing_operations_current",
        Title:    "Indexing Operations Current",
        Units:    "operations",
        Fam:      "indices indexing",
        Ctx:      "elasticsearch.node_indices_indexing_current",
        Priority: prioNodeIndicesIndexingOpsCurrent,
        Dims: module.Dims{
            {ID: "node_%s_indices_indexing_index_current", Name: "index"},
        },
    }
    nodeIndicesIndexingOpsTimeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_indexing_operations_time",
        Title:    "Time Spent On Indexing Operations",
        Units:    "milliseconds",
        Fam:      "indices indexing",
        Ctx:      "elasticsearch.node_indices_indexing_time",
        Priority: prioNodeIndicesIndexingOpsTime,
        Dims: module.Dims{
            {ID: "node_%s_indices_indexing_index_time_in_millis", Name: "index", Algo: module.Incremental},
        },
    }

    nodeIndicesSearchOpsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_search_operations",
        Title:    "Search Operations",
        Units:    "operations/s",
        Fam:      "indices search",
        Ctx:      "elasticsearch.node_indices_search",
        Type:     module.Stacked,
        Priority: prioNodeIndicesSearchOps,
        Dims: module.Dims{
            {ID: "node_%s_indices_search_query_total", Name: "queries", Algo: module.Incremental},
            {ID: "node_%s_indices_search_fetch_total", Name: "fetches", Algo: module.Incremental},
        },
    }
    nodeIndicesSearchOpsCurrentChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_search_operations_current",
        Title:    "Search Operations Current",
        Units:    "operations",
        Fam:      "indices search",
        Ctx:      "elasticsearch.node_indices_search_current",
        Type:     module.Stacked,
        Priority: prioNodeIndicesSearchOpsCurrent,
        Dims: module.Dims{
            {ID: "node_%s_indices_search_query_current", Name: "queries"},
            {ID: "node_%s_indices_search_fetch_current", Name: "fetches"},
        },
    }
    nodeIndicesSearchOpsTimeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_search_operations_time",
        Title:    "Time Spent On Search Operations",
        Units:    "milliseconds",
        Fam:      "indices search",
        Ctx:      "elasticsearch.node_indices_search_time",
        Type:     module.Stacked,
        Priority: prioNodeIndicesSearchOpsTime,
        Dims: module.Dims{
            {ID: "node_%s_indices_search_query_time_in_millis", Name: "query", Algo: module.Incremental},
            {ID: "node_%s_indices_search_fetch_time_in_millis", Name: "fetch", Algo: module.Incremental},
        },
    }

    nodeIndicesRefreshOpsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_refresh_operations",
        Title:    "Refresh Operations",
        Units:    "operations/s",
        Fam:      "indices refresh",
        Ctx:      "elasticsearch.node_indices_refresh",
        Priority: prioNodeIndicesRefreshOps,
        Dims: module.Dims{
            {ID: "node_%s_indices_refresh_total", Name: "refresh", Algo: module.Incremental},
        },
    }
    nodeIndicesRefreshOpsTimeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_refresh_operations_time",
        Title:    "Time Spent On Refresh Operations",
        Units:    "milliseconds",
        Fam:      "indices refresh",
        Ctx:      "elasticsearch.node_indices_refresh_time",
        Priority: prioNodeIndicesRefreshOpsTime,
        Dims: module.Dims{
            {ID: "node_%s_indices_refresh_total_time_in_millis", Name: "refresh", Algo: module.Incremental},
        },
    }

    nodeIndicesFlushOpsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_flush_operations",
        Title:    "Flush Operations",
        Units:    "operations/s",
        Fam:      "indices flush",
        Ctx:      "elasticsearch.node_indices_flush",
        Priority: prioNodeIndicesFlushOps,
        Dims: module.Dims{
            {ID: "node_%s_indices_flush_total", Name: "flush", Algo: module.Incremental},
        },
    }
    nodeIndicesFlushOpsTimeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_flush_operations_time",
        Title:    "Time Spent On Flush Operations",
        Units:    "milliseconds",
        Fam:      "indices flush",
        Ctx:      "elasticsearch.node_indices_flush_time",
        Priority: prioNodeIndicesFlushOpsTime,
        Dims: module.Dims{
            {ID: "node_%s_indices_flush_total_time_in_millis", Name: "flush", Algo: module.Incremental},
        },
    }

    nodeIndicesFieldDataMemoryUsageChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_fielddata_memory_usage",
        Title:    "Fielddata Cache Memory Usage",
        Units:    "bytes",
        Fam:      "indices fielddata",
        Ctx:      "elasticsearch.node_indices_fielddata_memory_usage",
        Type:     module.Area,
        Priority: prioNodeIndicesFieldDataMemoryUsage,
        Dims: module.Dims{
            {ID: "node_%s_indices_fielddata_memory_size_in_bytes", Name: "used"},
        },
    }
    nodeIndicesFieldDataEvictionsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_fielddata_evictions",
        Title:    "Fielddata Evictions",
        Units:    "operations/s",
        Fam:      "indices fielddata",
        Ctx:      "elasticsearch.node_indices_fielddata_evictions",
        Priority: prioNodeIndicesFieldDataEvictions,
        Dims: module.Dims{
            {ID: "node_%s_indices_fielddata_evictions", Name: "evictions", Algo: module.Incremental},
        },
    }

    nodeIndicesSegmentsCountChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_segments_count",
        Title:    "Segments Count",
        Units:    "segments",
        Fam:      "indices segments",
        Ctx:      "elasticsearch.node_indices_segments_count",
        Priority: prioNodeIndicesSegmentsCount,
        Dims: module.Dims{
            {ID: "node_%s_indices_segments_count", Name: "segments"},
        },
    }
    nodeIndicesSegmentsMemoryUsageTotalChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_segments_memory_usage_total",
        Title:    "Segments Memory Usage Total",
        Units:    "bytes",
        Fam:      "indices segments",
        Ctx:      "elasticsearch.node_indices_segments_memory_usage_total",
        Priority: prioNodeIndicesSegmentsMemoryUsageTotal,
        Dims: module.Dims{
            {ID: "node_%s_indices_segments_memory_in_bytes", Name: "used"},
        },
    }
    nodeIndicesSegmentsMemoryUsageChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_segments_memory_usage",
        Title:    "Segments Memory Usage",
        Units:    "bytes",
        Fam:      "indices segments",
        Ctx:      "elasticsearch.node_indices_segments_memory_usage",
        Type:     module.Stacked,
        Priority: prioNodeIndicesSegmentsMemoryUsage,
        Dims: module.Dims{
            {ID: "node_%s_indices_segments_terms_memory_in_bytes", Name: "terms"},
            {ID: "node_%s_indices_segments_stored_fields_memory_in_bytes", Name: "stored_fields"},
            {ID: "node_%s_indices_segments_term_vectors_memory_in_bytes", Name: "term_vectors"},
            {ID: "node_%s_indices_segments_norms_memory_in_bytes", Name: "norms"},
            {ID: "node_%s_indices_segments_points_memory_in_bytes", Name: "points"},
            {ID: "node_%s_indices_segments_doc_values_memory_in_bytes", Name: "doc_values"},
            {ID: "node_%s_indices_segments_index_writer_memory_in_bytes", Name: "index_writer"},
            {ID: "node_%s_indices_segments_version_map_memory_in_bytes", Name: "version_map"},
            {ID: "node_%s_indices_segments_fixed_bit_set_memory_in_bytes", Name: "fixed_bit_set"},
        },
    }

    nodeIndicesTransLogOpsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_indices_translog_operations",
        Title:    "Translog Operations",
        Units:    "operations",
        Fam:      "indices translog",
        Ctx:      "elasticsearch.node_indices_translog_operations",
        Type:     module.Area,
        Priority: prioNodeIndicesTransLogOps,
        Dims: module.Dims{
            {ID: "node_%s_indices_translog_operations", Name: "total"},
            {ID: "node_%s_indices_translog_uncommitted_operations", Name: "uncommitted"},
        },
    }
    nodeIndexTransLogSizeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_index_translog_size",
        Title:    "Translog Size",
        Units:    "bytes",
        Fam:      "indices translog",
        Ctx:      "elasticsearch.node_indices_translog_size",
        Type:     module.Area,
        Priority: prioNodeIndexTransLogSize,
        Dims: module.Dims{
            {ID: "node_%s_indices_translog_size_in_bytes", Name: "total"},
            {ID: "node_%s_indices_translog_uncommitted_size_in_bytes", Name: "uncommitted"},
        },
    }

    nodeFileDescriptorsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_file_descriptors",
        Title:    "Process File Descriptors",
        Units:    "fd",
        Fam:      "process",
        Ctx:      "elasticsearch.node_file_descriptors",
        Priority: prioNodeFileDescriptors,
        Dims: module.Dims{
            {ID: "node_%s_process_open_file_descriptors", Name: "open"},
        },
    }

    nodeJVMMemHeapChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_mem_heap",
        Title:    "JVM Heap Percentage Currently in Use",
        Units:    "percentage",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_heap",
        Type:     module.Area,
        Priority: prioNodeJVMMemHeap,
        Dims: module.Dims{
            {ID: "node_%s_jvm_mem_heap_used_percent", Name: "inuse"},
        },
    }
    nodeJVMMemHeapBytesChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_mem_heap_bytes",
        Title:    "JVM Heap Commit And Usage",
        Units:    "bytes",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_heap_bytes",
        Type:     module.Area,
        Priority: prioNodeJVMMemHeapBytes,
        Dims: module.Dims{
            {ID: "node_%s_jvm_mem_heap_committed_in_bytes", Name: "committed"},
            {ID: "node_%s_jvm_mem_heap_used_in_bytes", Name: "used"},
        },
    }
    nodeJVMBufferPoolsCountChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_buffer_pools_count",
        Title:    "JVM Buffer Pools Count",
        Units:    "pools",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_buffer_pools_count",
        Priority: prioNodeJVMBufferPoolsCount,
        Dims: module.Dims{
            {ID: "node_%s_jvm_buffer_pools_direct_count", Name: "direct"},
            {ID: "node_%s_jvm_buffer_pools_mapped_count", Name: "mapped"},
        },
    }
    nodeJVMBufferPoolDirectMemoryChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_buffer_pool_direct_memory",
        Title:    "JVM Buffer Pool Direct Memory",
        Units:    "bytes",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_buffer_pool_direct_memory",
        Type:     module.Area,
        Priority: prioNodeJVMBufferPoolDirectMemory,
        Dims: module.Dims{
            {ID: "node_%s_jvm_buffer_pools_direct_total_capacity_in_bytes", Name: "total"},
            {ID: "node_%s_jvm_buffer_pools_direct_used_in_bytes", Name: "used"},
        },
    }
    nodeJVMBufferPoolMappedMemoryChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_buffer_pool_mapped_memory",
        Title:    "JVM Buffer Pool Mapped Memory",
        Units:    "bytes",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_buffer_pool_mapped_memory",
        Type:     module.Area,
        Priority: prioNodeJVMBufferPoolMappedMemory,
        Dims: module.Dims{
            {ID: "node_%s_jvm_buffer_pools_mapped_total_capacity_in_bytes", Name: "total"},
            {ID: "node_%s_jvm_buffer_pools_mapped_used_in_bytes", Name: "used"},
        },
    }
    nodeJVMGCCountChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_gc_count",
        Title:    "JVM Garbage Collections",
        Units:    "gc/s",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_gc_count",
        Type:     module.Stacked,
        Priority: prioNodeJVMGCCount,
        Dims: module.Dims{
            {ID: "node_%s_jvm_gc_collectors_young_collection_count", Name: "young", Algo: module.Incremental},
            {ID: "node_%s_jvm_gc_collectors_old_collection_count", Name: "old", Algo: module.Incremental},
        },
    }
    nodeJVMGCTimeChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_jvm_gc_time",
        Title:    "JVM Time Spent On Garbage Collections",
        Units:    "milliseconds",
        Fam:      "jvm",
        Ctx:      "elasticsearch.node_jvm_gc_time",
        Type:     module.Stacked,
        Priority: prioNodeJVMGCTime,
        Dims: module.Dims{
            {ID: "node_%s_jvm_gc_collectors_young_collection_time_in_millis", Name: "young", Algo: module.Incremental},
            {ID: "node_%s_jvm_gc_collectors_old_collection_time_in_millis", Name: "old", Algo: module.Incremental},
        },
    }

    nodeThreadPoolQueuedChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_thread_pool_queued",
        Title:    "Thread Pool Queued Threads Count",
        Units:    "threads",
        Fam:      "thread pool",
        Ctx:      "elasticsearch.node_thread_pool_queued",
        Type:     module.Stacked,
        Priority: prioNodeThreadPoolQueued,
        Dims: module.Dims{
            {ID: "node_%s_thread_pool_generic_queue", Name: "generic"},
            {ID: "node_%s_thread_pool_search_queue", Name: "search"},
            {ID: "node_%s_thread_pool_search_throttled_queue", Name: "search_throttled"},
            {ID: "node_%s_thread_pool_get_queue", Name: "get"},
            {ID: "node_%s_thread_pool_analyze_queue", Name: "analyze"},
            {ID: "node_%s_thread_pool_write_queue", Name: "write"},
            {ID: "node_%s_thread_pool_snapshot_queue", Name: "snapshot"},
            {ID: "node_%s_thread_pool_warmer_queue", Name: "warmer"},
            {ID: "node_%s_thread_pool_refresh_queue", Name: "refresh"},
            {ID: "node_%s_thread_pool_listener_queue", Name: "listener"},
            {ID: "node_%s_thread_pool_fetch_shard_started_queue", Name: "fetch_shard_started"},
            {ID: "node_%s_thread_pool_fetch_shard_store_queue", Name: "fetch_shard_store"},
            {ID: "node_%s_thread_pool_flush_queue", Name: "flush"},
            {ID: "node_%s_thread_pool_force_merge_queue", Name: "force_merge"},
            {ID: "node_%s_thread_pool_management_queue", Name: "management"},
        },
    }
    nodeThreadPoolRejectedChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_thread_pool_rejected",
        Title:    "Thread Pool Rejected Threads Count",
        Units:    "threads",
        Fam:      "thread pool",
        Ctx:      "elasticsearch.node_thread_pool_rejected",
        Type:     module.Stacked,
        Priority: prioNodeThreadPoolRejected,
        Dims: module.Dims{
            {ID: "node_%s_thread_pool_generic_rejected", Name: "generic"},
            {ID: "node_%s_thread_pool_search_rejected", Name: "search"},
            {ID: "node_%s_thread_pool_search_throttled_rejected", Name: "search_throttled"},
            {ID: "node_%s_thread_pool_get_rejected", Name: "get"},
            {ID: "node_%s_thread_pool_analyze_rejected", Name: "analyze"},
            {ID: "node_%s_thread_pool_write_rejected", Name: "write"},
            {ID: "node_%s_thread_pool_snapshot_rejected", Name: "snapshot"},
            {ID: "node_%s_thread_pool_warmer_rejected", Name: "warmer"},
            {ID: "node_%s_thread_pool_refresh_rejected", Name: "refresh"},
            {ID: "node_%s_thread_pool_listener_rejected", Name: "listener"},
            {ID: "node_%s_thread_pool_fetch_shard_started_rejected", Name: "fetch_shard_started"},
            {ID: "node_%s_thread_pool_fetch_shard_store_rejected", Name: "fetch_shard_store"},
            {ID: "node_%s_thread_pool_flush_rejected", Name: "flush"},
            {ID: "node_%s_thread_pool_force_merge_rejected", Name: "force_merge"},
            {ID: "node_%s_thread_pool_management_rejected", Name: "management"},
        },
    }

    nodeClusterCommunicationPacketsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_cluster_communication_packets",
        Title:    "Node Cluster Communication",
        Units:    "pps",
        Fam:      "transport",
        Ctx:      "elasticsearch.node_cluster_communication_packets",
        Priority: prioNodeClusterCommunicationPackets,
        Dims: module.Dims{
            {ID: "node_%s_transport_rx_count", Name: "received", Algo: module.Incremental},
            {ID: "node_%s_transport_tx_count", Name: "sent", Mul: -1, Algo: module.Incremental},
        },
    }
    nodeClusterCommunicationChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_cluster_communication_traffic",
        Title:    "Cluster Communication Bandwidth",
        Units:    "bytes/s",
        Fam:      "transport",
        Ctx:      "elasticsearch.node_cluster_communication_traffic",
        Priority: prioNodeClusterCommunication,
        Dims: module.Dims{
            {ID: "node_%s_transport_rx_size_in_bytes", Name: "received", Algo: module.Incremental},
            {ID: "node_%s_transport_tx_size_in_bytes", Name: "sent", Mul: -1, Algo: module.Incremental},
        },
    }

    nodeHTTPConnectionsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_http_connections",
        Title:    "HTTP Connections",
        Units:    "connections",
        Fam:      "http",
        Ctx:      "elasticsearch.node_http_connections",
        Priority: prioNodeHTTPConnections,
        Dims: module.Dims{
            {ID: "node_%s_http_current_open", Name: "open"},
        },
    }

    nodeBreakersTripsChartTmpl = module.Chart{
        ID:       "node_%s_cluster_%s_breakers_trips",
        Title:    "Circuit Breaker Trips Count",
        Units:    "trips/s",
        Fam:      "circuit breakers",
        Ctx:      "elasticsearch.node_breakers_trips",
        Type:     module.Stacked,
        Priority: prioNodeBreakersTrips,
        Dims: module.Dims{
            {ID: "node_%s_breakers_request_tripped", Name: "requests", Algo: module.Incremental},
            {ID: "node_%s_breakers_fielddata_tripped", Name: "fielddata", Algo: module.Incremental},
            {ID: "node_%s_breakers_in_flight_requests_tripped", Name: "in_flight_requests", Algo: module.Incremental},
            {ID: "node_%s_breakers_model_inference_tripped", Name: "model_inference", Algo: module.Incremental},
            {ID: "node_%s_breakers_accounting_tripped", Name: "accounting", Algo: module.Incremental},
            {ID: "node_%s_breakers_parent_tripped", Name: "parent", Algo: module.Incremental},
        },
    }
)

var clusterHealthChartsTmpl = module.Charts{
    clusterStatusChartTmpl.Copy(),
    clusterNodesCountChartTmpl.Copy(),
    clusterShardsCountChartTmpl.Copy(),
    clusterPendingTasksChartTmpl.Copy(),
    clusterInFlightFetchesCountChartTmpl.Copy(),
}

var (
    clusterStatusChartTmpl = module.Chart{
        ID:       "cluster_%s_status",
        Title:    "Cluster Status",
        Units:    "status",
        Fam:      "cluster health",
        Ctx:      "elasticsearch.cluster_health_status",
        Priority: prioClusterStatus,
        Dims: module.Dims{
            {ID: "cluster_status_green", Name: "green"},
            {ID: "cluster_status_red", Name: "red"},
            {ID: "cluster_status_yellow", Name: "yellow"},
        },
    }
    clusterNodesCountChartTmpl = module.Chart{
        ID:       "cluster_%s_number_of_nodes",
        Title:    "Cluster Nodes Count",
        Units:    "nodes",
        Fam:      "cluster health",
        Ctx:      "elasticsearch.cluster_number_of_nodes",
        Priority: prioClusterNodesCount,
        Dims: module.Dims{
            {ID: "cluster_number_of_nodes", Name: "nodes"},
            {ID: "cluster_number_of_data_nodes", Name: "data_nodes"},
        },
    }
    clusterShardsCountChartTmpl = module.Chart{
        ID:       "cluster_%s_shards_count",
        Title:    "Cluster Shards Count",
        Units:    "shards",
        Fam:      "cluster health",
        Ctx:      "elasticsearch.cluster_shards_count",
        Priority: prioClusterShardsCount,
        Dims: module.Dims{
            {ID: "cluster_active_primary_shards", Name: "active_primary"},
            {ID: "cluster_active_shards", Name: "active"},
            {ID: "cluster_relocating_shards", Name: "relocating"},
            {ID: "cluster_initializing_shards", Name: "initializing"},
            {ID: "cluster_unassigned_shards", Name: "unassigned"},
            {ID: "cluster_delayed_unassigned_shards", Name: "delayed_unassigned"},
        },
    }
    clusterPendingTasksChartTmpl = module.Chart{
        ID:       "cluster_%s_pending_tasks",
        Title:    "Cluster Pending Tasks",
        Units:    "tasks",
        Fam:      "cluster health",
        Ctx:      "elasticsearch.cluster_pending_tasks",
        Priority: prioClusterPendingTasks,
        Dims: module.Dims{
            {ID: "cluster_number_of_pending_tasks", Name: "pending"},
        },
    }
    clusterInFlightFetchesCountChartTmpl = module.Chart{
        ID:       "cluster_%s_number_of_in_flight_fetch",
        Title:    "Cluster Unfinished Fetches",
        Units:    "fetches",
        Fam:      "cluster health",
        Ctx:      "elasticsearch.cluster_number_of_in_flight_fetch",
        Priority: prioClusterInFlightFetchesCount,
        Dims: module.Dims{
            {ID: "cluster_number_of_in_flight_fetch", Name: "in_flight_fetch"},
        },
    }
)

var clusterStatsChartsTmpl = module.Charts{
    clusterIndicesCountChartTmpl.Copy(),
    clusterIndicesShardsCountChartTmpl.Copy(),
    clusterIndicesDocsCountChartTmpl.Copy(),
    clusterIndicesStoreSizeChartTmpl.Copy(),
    clusterIndicesQueryCacheChartTmpl.Copy(),
    clusterNodesByRoleCountChartTmpl.Copy(),
}

var (
    clusterIndicesCountChartTmpl = module.Chart{
        ID:       "cluster_%s_indices_count",
        Title:    "Cluster Indices Count",
        Units:    "indices",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_indices_count",
        Priority: prioClusterIndicesCount,
        Dims: module.Dims{
            {ID: "cluster_indices_count", Name: "indices"},
        },
    }
    clusterIndicesShardsCountChartTmpl = module.Chart{
        ID:       "cluster_%s_indices_shards_count",
        Title:    "Cluster Indices Shards Count",
        Units:    "shards",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_indices_shards_count",
        Priority: prioClusterIndicesShardsCount,
        Dims: module.Dims{
            {ID: "cluster_indices_shards_total", Name: "total"},
            {ID: "cluster_indices_shards_primaries", Name: "primaries"},
            {ID: "cluster_indices_shards_replication", Name: "replication"},
        },
    }
    clusterIndicesDocsCountChartTmpl = module.Chart{
        ID:       "cluster_%s_indices_docs_count",
        Title:    "Cluster Indices Docs Count",
        Units:    "docs",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_indices_docs_count",
        Priority: prioClusterIndicesDocsCount,
        Dims: module.Dims{
            {ID: "cluster_indices_docs_count", Name: "docs"},
        },
    }
    clusterIndicesStoreSizeChartTmpl = module.Chart{
        ID:       "cluster_%s_indices_store_size",
        Title:    "Cluster Indices Store Size",
        Units:    "bytes",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_indices_store_size",
        Priority: prioClusterIndicesStoreSize,
        Dims: module.Dims{
            {ID: "cluster_indices_store_size_in_bytes", Name: "size"},
        },
    }
    clusterIndicesQueryCacheChartTmpl = module.Chart{
        ID:       "cluster_%s_indices_query_cache",
        Title:    "Cluster Indices Query Cache",
        Units:    "events/s",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_indices_query_cache",
        Type:     module.Stacked,
        Priority: prioClusterIndicesQueryCache,
        Dims: module.Dims{
            {ID: "cluster_indices_query_cache_hit_count", Name: "hit", Algo: module.Incremental},
            {ID: "cluster_indices_query_cache_miss_count", Name: "miss", Algo: module.Incremental},
        },
    }
    clusterNodesByRoleCountChartTmpl = module.Chart{
        ID:       "cluster_%s_nodes_by_role_count",
        Title:    "Cluster Nodes By Role Count",
        Units:    "nodes",
        Fam:      "cluster stats",
        Ctx:      "elasticsearch.cluster_nodes_by_role_count",
        Priority: prioClusterNodesByRoleCount,
        Dims: module.Dims{
            {ID: "cluster_nodes_count_coordinating_only", Name: "coordinating_only"},
            {ID: "cluster_nodes_count_data", Name: "data"},
            {ID: "cluster_nodes_count_data_cold", Name: "data_cold"},
            {ID: "cluster_nodes_count_data_content", Name: "data_content"},
            {ID: "cluster_nodes_count_data_frozen", Name: "data_frozen"},
            {ID: "cluster_nodes_count_data_hot", Name: "data_hot"},
            {ID: "cluster_nodes_count_data_warm", Name: "data_warm"},
            {ID: "cluster_nodes_count_ingest", Name: "ingest"},
            {ID: "cluster_nodes_count_master", Name: "master"},
            {ID: "cluster_nodes_count_ml", Name: "ml"},
            {ID: "cluster_nodes_count_remote_cluster_client", Name: "remote_cluster_client"},
            {ID: "cluster_nodes_count_voting_only", Name: "voting_only"},
        },
    }
)

var nodeIndexChartsTmpl = module.Charts{
    nodeIndexHealthChartTmpl.Copy(),
    nodeIndexShardsCountChartTmpl.Copy(),
    nodeIndexDocsCountChartTmpl.Copy(),
    nodeIndexStoreSizeChartTmpl.Copy(),
}

var (
    nodeIndexHealthChartTmpl = module.Chart{
        ID:       "node_index_%s_cluster_%s_health",
        Title:    "Index Health",
        Units:    "status",
        Fam:      "index stats",
        Ctx:      "elasticsearch.node_index_health",
        Priority: prioNodeIndexHealth,
        Dims: module.Dims{
            {ID: "node_index_%s_stats_health_green", Name: "green"},
            {ID: "node_index_%s_stats_health_red", Name: "red"},
            {ID: "node_index_%s_stats_health_yellow", Name: "yellow"},
        },
    }
    nodeIndexShardsCountChartTmpl = module.Chart{
        ID:       "node_index_%s_cluster_%s_shards_count",
        Title:    "Index Shards Count",
        Units:    "shards",
        Fam:      "index stats",
        Ctx:      "elasticsearch.node_index_shards_count",
        Priority: prioNodeIndexShardsCount,
        Dims: module.Dims{
            {ID: "node_index_%s_stats_shards_count", Name: "shards"},
        },
    }
    nodeIndexDocsCountChartTmpl = module.Chart{
        ID:       "node_index_%s_cluster_%s_docs_count",
        Title:    "Index Docs Count",
        Units:    "docs",
        Fam:      "index stats",
        Ctx:      "elasticsearch.node_index_docs_count",
        Priority: prioNodeIndexDocsCount,
        Dims: module.Dims{
            {ID: "node_index_%s_stats_docs_count", Name: "docs"},
        },
    }
    nodeIndexStoreSizeChartTmpl = module.Chart{
        ID:       "node_index_%s_cluster_%s_store_size",
        Title:    "Index Store Size",
        Units:    "bytes",
        Fam:      "index stats",
        Ctx:      "elasticsearch.node_index_store_size",
        Priority: prioNodeIndexStoreSize,
        Dims: module.Dims{
            {ID: "node_index_%s_stats_store_size_in_bytes", Name: "store_size"},
        },
    }
)

func (es *Elasticsearch) addClusterStatsCharts() {
    charts := clusterStatsChartsTmpl.Copy()

    for _, chart := range *charts {
        chart.ID = fmt.Sprintf(chart.ID, es.clusterName)
        chart.Labels = []module.Label{
            {Key: "cluster_name", Value: es.clusterName},
        }
    }

    if err := es.charts.Add(*charts...); err != nil {
        es.Warning(err)
    }
}

func (es *Elasticsearch) addClusterHealthCharts() {
    charts := clusterHealthChartsTmpl.Copy()

    for _, chart := range *charts {
        chart.ID = fmt.Sprintf(chart.ID, es.clusterName)
        chart.Labels = []module.Label{
            {Key: "cluster_name", Value: es.clusterName},
        }
    }

    if err := es.charts.Add(*charts...); err != nil {
        es.Warning(err)
    }
}

func (es *Elasticsearch) addNodeCharts(nodeID string, node *esNodeStats) {
    charts := nodeChartsTmpl.Copy()

    for _, chart := range *charts {
        chart.ID = fmt.Sprintf(chart.ID, nodeID, es.clusterName)
        chart.Labels = []module.Label{
            {Key: "cluster_name", Value: es.clusterName},
            {Key: "node_name", Value: node.Name},
            {Key: "host", Value: node.Host},
        }
        for _, dim := range chart.Dims {
            dim.ID = fmt.Sprintf(dim.ID, nodeID)
        }
    }

    if err := es.Charts().Add(*charts...); err != nil {
        es.Warning(err)
    }
}

func (es *Elasticsearch) removeNodeCharts(nodeID string) {
    px := fmt.Sprintf("node_%s_cluster_%s_", nodeID, es.clusterName)
    es.removeCharts(px)
}

func (es *Elasticsearch) addIndexCharts(index string) {
    charts := nodeIndexChartsTmpl.Copy()

    for _, chart := range *charts {
        chart.ID = fmt.Sprintf(chart.ID, index, es.clusterName)
        chart.Labels = []module.Label{
            {Key: "cluster_name", Value: es.clusterName},
            {Key: "index", Value: index},
        }
        for _, dim := range chart.Dims {
            dim.ID = fmt.Sprintf(dim.ID, index)
        }
    }

    if err := es.Charts().Add(*charts...); err != nil {
        es.Warning(err)
    }
}

func (es *Elasticsearch) removeIndexCharts(index string) {
    px := fmt.Sprintf("node_index_%s_cluster_%s_", index, es.clusterName)
    es.removeCharts(px)
}

func (es *Elasticsearch) removeCharts(prefix string) {
    for _, chart := range *es.Charts() {
        if strings.HasPrefix(chart.ID, prefix) {
            chart.MarkRemove()
            chart.MarkNotCreated()
        }
    }
}