github.com/netdata/go.d.plugin@v0.58.1/modules/pulsar/charts.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package pulsar
     4  
     5  import (
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/netdata/go.d.plugin/pkg/prometheus"
    10  
    11  	"github.com/netdata/go.d.plugin/agent/module"
    12  )
    13  
    14  type (
    15  	Charts = module.Charts
    16  	Chart  = module.Chart
    17  	Dims   = module.Dims
    18  	Dim    = module.Dim
    19  	Opts   = module.Opts
    20  )
    21  
    22  var summaryCharts = Charts{
    23  	sumBrokerComponentsChart.Copy(),
    24  
    25  	sumMessagesRateChart.Copy(),
    26  	sumThroughputRateChart.Copy(),
    27  
    28  	sumStorageSizeChart.Copy(),
    29  	sumStorageOperationsRateChart.Copy(), // optional
    30  	sumMsgBacklogSizeChart.Copy(),
    31  	sumStorageWriteLatencyChart.Copy(),
    32  	sumEntrySizeChart.Copy(),
    33  
    34  	sumSubsDelayedChart.Copy(),
    35  	sumSubsMsgRateRedeliverChart.Copy(),    // optional
    36  	sumSubsBlockedOnUnackedMsgChart.Copy(), // optional
    37  
    38  	sumReplicationRateChart.Copy(),           // optional
    39  	sumReplicationThroughputRateChart.Copy(), // optional
    40  	sumReplicationBacklogChart.Copy(),        // optional
    41  }
    42  
    43  var (
    44  	sumBrokerComponentsChart = Chart{
    45  		ID:    "broker_components",
    46  		Title: "Broker Components",
    47  		Units: "components",
    48  		Fam:   "ns summary",
    49  		Ctx:   "pulsar.broker_components",
    50  		Type:  module.Stacked,
    51  		Opts:  Opts{StoreFirst: true},
    52  		Dims: Dims{
    53  			{ID: "pulsar_namespaces_count", Name: "namespaces"},
    54  			{ID: metricPulsarTopicsCount, Name: "topics"},
    55  			{ID: metricPulsarSubscriptionsCount, Name: "subscriptions"},
    56  			{ID: metricPulsarProducersCount, Name: "producers"},
    57  			{ID: metricPulsarConsumersCount, Name: "consumers"},
    58  		},
    59  	}
    60  	sumMessagesRateChart = Chart{
    61  		ID:    "messages_rate",
    62  		Title: "Messages Rate",
    63  		Units: "messages/s",
    64  		Fam:   "ns summary",
    65  		Ctx:   "pulsar.messages_rate",
    66  		Opts:  Opts{StoreFirst: true},
    67  		Dims: Dims{
    68  			{ID: metricPulsarRateIn, Name: "publish", Div: 1000},
    69  			{ID: metricPulsarRateOut, Name: "dispatch", Mul: -1, Div: 1000},
    70  		},
    71  	}
    72  	sumThroughputRateChart = Chart{
    73  		ID:    "throughput_rate",
    74  		Title: "Throughput Rate",
    75  		Units: "KiB/s",
    76  		Fam:   "ns summary",
    77  		Ctx:   "pulsar.throughput_rate",
    78  		Type:  module.Area,
    79  		Opts:  Opts{StoreFirst: true},
    80  		Dims: Dims{
    81  			{ID: metricPulsarThroughputIn, Name: "publish", Div: 1024 * 1000},
    82  			{ID: metricPulsarThroughputOut, Name: "dispatch", Mul: -1, Div: 1024 * 1000},
    83  		},
    84  	}
    85  	sumStorageSizeChart = Chart{
    86  		ID:    "storage_size",
    87  		Title: "Storage Size",
    88  		Units: "KiB",
    89  		Fam:   "ns summary",
    90  		Ctx:   "pulsar.storage_size",
    91  		Opts:  Opts{StoreFirst: true},
    92  		Dims: Dims{
    93  			{ID: metricPulsarStorageSize, Name: "used", Div: 1024},
    94  		},
    95  	}
    96  	sumStorageOperationsRateChart = Chart{
    97  		ID:    "storage_operations_rate",
    98  		Title: "Storage Read/Write Operations Rate",
    99  		Units: "message batches/s",
   100  		Fam:   "ns summary",
   101  		Ctx:   "pulsar.storage_operations_rate",
   102  		Type:  module.Area,
   103  		Opts:  Opts{StoreFirst: true},
   104  		Dims: Dims{
   105  			{ID: metricPulsarStorageReadRate, Name: "read", Div: 1000},
   106  			{ID: metricPulsarStorageWriteRate, Name: "write", Mul: -1, Div: 1000},
   107  		},
   108  	}
   109  	sumMsgBacklogSizeChart = Chart{
   110  		ID:    "msg_backlog",
   111  		Title: "Messages Backlog Size",
   112  		Units: "messages",
   113  		Fam:   "ns summary",
   114  		Ctx:   "pulsar.msg_backlog",
   115  		Opts:  Opts{StoreFirst: true},
   116  		Dims: Dims{
   117  			{ID: metricPulsarMsgBacklog, Name: "backlog"},
   118  		},
   119  	}
   120  	sumStorageWriteLatencyChart = Chart{
   121  		ID:    "storage_write_latency",
   122  		Title: "Storage Write Latency",
   123  		Units: "entries/s",
   124  		Fam:   "ns summary",
   125  		Ctx:   "pulsar.storage_write_latency",
   126  		Type:  module.Stacked,
   127  		Opts:  Opts{StoreFirst: true},
   128  		Dims: Dims{
   129  			{ID: "pulsar_storage_write_latency_le_0_5", Name: "<=0.5ms", Div: 60},
   130  			{ID: "pulsar_storage_write_latency_le_1", Name: "<=1ms", Div: 60},
   131  			{ID: "pulsar_storage_write_latency_le_5", Name: "<=5ms", Div: 60},
   132  			{ID: "pulsar_storage_write_latency_le_10", Name: "<=10ms", Div: 60},
   133  			{ID: "pulsar_storage_write_latency_le_20", Name: "<=20ms", Div: 60},
   134  			{ID: "pulsar_storage_write_latency_le_50", Name: "<=50ms", Div: 60},
   135  			{ID: "pulsar_storage_write_latency_le_100", Name: "<=100ms", Div: 60},
   136  			{ID: "pulsar_storage_write_latency_le_200", Name: "<=200ms", Div: 60},
   137  			{ID: "pulsar_storage_write_latency_le_1000", Name: "<=1s", Div: 60},
   138  			{ID: "pulsar_storage_write_latency_overflow", Name: ">1s", Div: 60},
   139  		},
   140  	}
   141  	sumEntrySizeChart = Chart{
   142  		ID:    "entry_size",
   143  		Title: "Entry Size",
   144  		Units: "entries/s",
   145  		Fam:   "ns summary",
   146  		Ctx:   "pulsar.entry_size",
   147  		Type:  module.Stacked,
   148  		Opts:  Opts{StoreFirst: true},
   149  		Dims: Dims{
   150  			{ID: "pulsar_entry_size_le_128", Name: "<=128B", Div: 60},
   151  			{ID: "pulsar_entry_size_le_512", Name: "<=512B", Div: 60},
   152  			{ID: "pulsar_entry_size_le_1_kb", Name: "<=1KB", Div: 60},
   153  			{ID: "pulsar_entry_size_le_2_kb", Name: "<=2KB", Div: 60},
   154  			{ID: "pulsar_entry_size_le_4_kb", Name: "<=4KB", Div: 60},
   155  			{ID: "pulsar_entry_size_le_16_kb", Name: "<=16KB", Div: 60},
   156  			{ID: "pulsar_entry_size_le_100_kb", Name: "<=100KB", Div: 60},
   157  			{ID: "pulsar_entry_size_le_1_mb", Name: "<=1MB", Div: 60},
   158  			{ID: "pulsar_entry_size_le_overflow", Name: ">1MB", Div: 60},
   159  		},
   160  	}
   161  	sumSubsDelayedChart = Chart{
   162  		ID:    "subscription_delayed",
   163  		Title: "Subscriptions Delayed for Dispatching",
   164  		Units: "message batches",
   165  		Fam:   "ns summary",
   166  		Ctx:   "pulsar.subscription_delayed",
   167  		Opts:  Opts{StoreFirst: true},
   168  		Dims: Dims{
   169  			{ID: metricPulsarSubscriptionDelayed, Name: "delayed"},
   170  		},
   171  	}
   172  	sumSubsMsgRateRedeliverChart = Chart{
   173  		ID:    "subscription_msg_rate_redeliver",
   174  		Title: "Subscriptions Redelivered Message Rate",
   175  		Units: "messages/s",
   176  		Fam:   "ns summary",
   177  		Ctx:   "pulsar.subscription_msg_rate_redeliver",
   178  		Opts:  Opts{StoreFirst: true},
   179  		Dims: Dims{
   180  			{ID: metricPulsarSubscriptionMsgRateRedeliver, Name: "redelivered", Div: 1000},
   181  		},
   182  	}
   183  	sumSubsBlockedOnUnackedMsgChart = Chart{
   184  		ID:    "subscription_blocked_on_unacked_messages",
   185  		Title: "Subscriptions Blocked On Unacked Messages",
   186  		Units: "subscriptions",
   187  		Fam:   "ns summary",
   188  		Ctx:   "pulsar.subscription_blocked_on_unacked_messages",
   189  		Opts:  Opts{StoreFirst: true},
   190  		Dims: Dims{
   191  			{ID: metricPulsarSubscriptionBlockedOnUnackedMessages, Name: "blocked"},
   192  		},
   193  	}
   194  	sumReplicationRateChart = Chart{
   195  		ID:    "replication_rate",
   196  		Title: "Replication Rate",
   197  		Units: "messages/s",
   198  		Fam:   "ns summary",
   199  		Ctx:   "pulsar.replication_rate",
   200  		Opts:  Opts{StoreFirst: true},
   201  		Dims: Dims{
   202  			{ID: metricPulsarReplicationRateIn, Name: "in", Div: 1000},
   203  			{ID: metricPulsarReplicationRateOut, Name: "out", Mul: -1, Div: 1000},
   204  		},
   205  	}
   206  	sumReplicationThroughputRateChart = Chart{
   207  		ID:    "replication_throughput_rate",
   208  		Title: "Replication Throughput Rate",
   209  		Units: "KiB/s",
   210  		Fam:   "ns summary",
   211  		Ctx:   "pulsar.replication_throughput_rate",
   212  		Opts:  Opts{StoreFirst: true},
   213  		Dims: Dims{
   214  			{ID: metricPulsarReplicationThroughputIn, Name: "in", Div: 1024 * 1000},
   215  			{ID: metricPulsarReplicationThroughputOut, Name: "out", Mul: -1, Div: 1024 * 1000},
   216  		},
   217  	}
   218  	sumReplicationBacklogChart = Chart{
   219  		ID:    "replication_backlog",
   220  		Title: "Replication Backlog",
   221  		Units: "messages",
   222  		Fam:   "ns summary",
   223  		Ctx:   "pulsar.replication_backlog",
   224  		Opts:  Opts{StoreFirst: true},
   225  		Dims: Dims{
   226  			{ID: metricPulsarReplicationBacklog, Name: "backlog"},
   227  		},
   228  	}
   229  )
   230  
   231  var namespaceCharts = Charts{
   232  	nsBrokerComponentsChart.Copy(),
   233  	topicProducersChart.Copy(),
   234  	topicSubscriptionsChart.Copy(),
   235  	topicConsumersChart.Copy(),
   236  
   237  	nsMessagesRateChart.Copy(),
   238  	topicMessagesRateInChart.Copy(),
   239  	topicMessagesRateOutChart.Copy(),
   240  	nsThroughputRateCharts.Copy(),
   241  	topicThroughputRateInChart.Copy(),
   242  	topicThroughputRateOutChart.Copy(),
   243  
   244  	nsStorageSizeChart.Copy(),
   245  	topicStorageSizeChart.Copy(),
   246  	nsStorageOperationsChart.Copy(),   // optional
   247  	topicStorageReadRateChart.Copy(),  // optional
   248  	topicStorageWriteRateChart.Copy(), // optional
   249  	nsMsgBacklogSizeChart.Copy(),
   250  	topicMsgBacklogSizeChart.Copy(),
   251  	nsStorageWriteLatencyChart.Copy(),
   252  	nsEntrySizeChart.Copy(),
   253  
   254  	nsSubsDelayedChart.Copy(),
   255  	topicSubsDelayedChart.Copy(),
   256  	nsSubsMsgRateRedeliverChart.Copy(),       // optional
   257  	topicSubsMsgRateRedeliverChart.Copy(),    // optional
   258  	nsSubsBlockedOnUnackedMsgChart.Copy(),    // optional
   259  	topicSubsBlockedOnUnackedMsgChart.Copy(), // optional
   260  
   261  	nsReplicationRateChart.Copy(),                 // optional
   262  	topicReplicationRateInChart.Copy(),            // optional
   263  	topicReplicationRateOutChart.Copy(),           // optional
   264  	nsReplicationThroughputChart.Copy(),           // optional
   265  	topicReplicationThroughputRateInChart.Copy(),  // optional
   266  	topicReplicationThroughputRateOutChart.Copy(), // optional
   267  	nsReplicationBacklogChart.Copy(),              // optional
   268  	topicReplicationBacklogChart.Copy(),           // optional
   269  }
   270  
   271  func toNamespaceChart(chart Chart) Chart {
   272  	if chart.ID == sumBrokerComponentsChart.ID {
   273  		_ = chart.RemoveDim("pulsar_namespaces_count")
   274  	}
   275  	chart.ID += "_namespace_%s"
   276  	chart.Fam = "ns %s"
   277  	if idx := strings.IndexByte(chart.Ctx, '.'); idx > 0 {
   278  		// pulsar.messages_rate => pulsar.namespace_messages_rate
   279  		chart.Ctx = chart.Ctx[:idx+1] + "namespace_" + chart.Ctx[idx+1:]
   280  	}
   281  	for _, dim := range chart.Dims {
   282  		dim.ID += "_%s"
   283  	}
   284  	return chart
   285  }
   286  
   287  var (
   288  	nsBrokerComponentsChart        = toNamespaceChart(sumBrokerComponentsChart)
   289  	nsMessagesRateChart            = toNamespaceChart(sumMessagesRateChart)
   290  	nsThroughputRateCharts         = toNamespaceChart(sumThroughputRateChart)
   291  	nsStorageSizeChart             = toNamespaceChart(sumStorageSizeChart)
   292  	nsStorageOperationsChart       = toNamespaceChart(sumStorageOperationsRateChart)
   293  	nsMsgBacklogSizeChart          = toNamespaceChart(sumMsgBacklogSizeChart)
   294  	nsStorageWriteLatencyChart     = toNamespaceChart(sumStorageWriteLatencyChart)
   295  	nsEntrySizeChart               = toNamespaceChart(sumEntrySizeChart)
   296  	nsSubsDelayedChart             = toNamespaceChart(sumSubsDelayedChart)
   297  	nsSubsMsgRateRedeliverChart    = toNamespaceChart(sumSubsMsgRateRedeliverChart)
   298  	nsSubsBlockedOnUnackedMsgChart = toNamespaceChart(sumSubsBlockedOnUnackedMsgChart)
   299  	nsReplicationRateChart         = toNamespaceChart(sumReplicationRateChart)
   300  	nsReplicationThroughputChart   = toNamespaceChart(sumReplicationThroughputRateChart)
   301  	nsReplicationBacklogChart      = toNamespaceChart(sumReplicationBacklogChart)
   302  
   303  	topicProducersChart = Chart{
   304  		ID:    "topic_producers_namespace_%s",
   305  		Title: "Topic Producers",
   306  		Units: "producers",
   307  		Fam:   "ns %s",
   308  		Ctx:   "pulsar.topic_producers",
   309  		Type:  module.Stacked,
   310  		Opts:  Opts{StoreFirst: true},
   311  	}
   312  	topicSubscriptionsChart = Chart{
   313  		ID:    "topic_subscriptions_namespace_%s",
   314  		Title: "Topic Subscriptions",
   315  		Units: "subscriptions",
   316  		Fam:   "ns %s",
   317  		Ctx:   "pulsar.topic_subscriptions",
   318  		Type:  module.Stacked,
   319  		Opts:  Opts{StoreFirst: true},
   320  	}
   321  	topicConsumersChart = Chart{
   322  		ID:    "topic_consumers_namespace_%s",
   323  		Title: "Topic Consumers",
   324  		Units: "consumers",
   325  		Fam:   "ns %s",
   326  		Ctx:   "pulsar.topic_consumers",
   327  		Type:  module.Stacked,
   328  		Opts:  Opts{StoreFirst: true},
   329  	}
   330  	topicMessagesRateInChart = Chart{
   331  		ID:    "topic_messages_rate_in_namespace_%s",
   332  		Title: "Topic Publish Messages Rate",
   333  		Units: "publishes/s",
   334  		Fam:   "ns %s",
   335  		Ctx:   "pulsar.topic_messages_rate_in",
   336  		Type:  module.Stacked,
   337  		Opts:  Opts{StoreFirst: true},
   338  	}
   339  	topicMessagesRateOutChart = Chart{
   340  		ID:    "topic_messages_rate_out_namespace_%s",
   341  		Title: "Topic Dispatch Messages Rate",
   342  		Units: "dispatches/s",
   343  		Fam:   "ns %s",
   344  		Ctx:   "pulsar.topic_messages_rate_out",
   345  		Type:  module.Stacked,
   346  		Opts:  Opts{StoreFirst: true},
   347  	}
   348  	topicThroughputRateInChart = Chart{
   349  		ID:    "topic_throughput_rate_in_namespace_%s",
   350  		Title: "Topic Publish Throughput Rate",
   351  		Units: "KiB/s",
   352  		Fam:   "ns %s",
   353  		Ctx:   "pulsar.topic_throughput_rate_in",
   354  		Type:  module.Stacked,
   355  		Opts:  Opts{StoreFirst: true},
   356  	}
   357  	topicThroughputRateOutChart = Chart{
   358  		ID:    "topic_throughput_rate_out_namespace_%s",
   359  		Title: "Topic Dispatch Throughput Rate",
   360  		Units: "KiB/s",
   361  		Fam:   "ns %s",
   362  		Ctx:   "pulsar.topic_throughput_rate_out",
   363  		Type:  module.Stacked,
   364  		Opts:  Opts{StoreFirst: true},
   365  	}
   366  	topicStorageSizeChart = Chart{
   367  		ID:    "topic_storage_size_namespace_%s",
   368  		Title: "Topic Storage Size",
   369  		Units: "KiB",
   370  		Fam:   "ns %s",
   371  		Ctx:   "pulsar.topic_storage_size",
   372  		Type:  module.Stacked,
   373  		Opts:  Opts{StoreFirst: true},
   374  	}
   375  	topicStorageReadRateChart = Chart{
   376  		ID:    "topic_storage_read_rate_namespace_%s",
   377  		Title: "Topic Storage Read Rate",
   378  		Units: "message batches/s",
   379  		Fam:   "ns %s",
   380  		Ctx:   "pulsar.topic_storage_read_rate",
   381  		Type:  module.Stacked,
   382  		Opts:  Opts{StoreFirst: true},
   383  	}
   384  	topicStorageWriteRateChart = Chart{
   385  		ID:    "topic_storage_write_rate_namespace_%s",
   386  		Title: "Topic Storage Write Rate",
   387  		Units: "message batches/s",
   388  		Fam:   "ns %s",
   389  		Ctx:   "pulsar.topic_storage_write_rate",
   390  		Type:  module.Stacked,
   391  		Opts:  Opts{StoreFirst: true},
   392  	}
   393  	topicMsgBacklogSizeChart = Chart{
   394  		ID:    "topic_msg_backlog_namespace_%s",
   395  		Title: "Topic Messages Backlog Size",
   396  		Units: "messages",
   397  		Fam:   "ns %s",
   398  		Ctx:   "pulsar.topic_msg_backlog",
   399  		Type:  module.Stacked,
   400  		Opts:  Opts{StoreFirst: true},
   401  	}
   402  	topicSubsDelayedChart = Chart{
   403  		ID:    "topic_subscription_delayed_namespace_%s",
   404  		Title: "Topic Subscriptions Delayed for Dispatching",
   405  		Units: "message batches",
   406  		Fam:   "ns %s",
   407  		Ctx:   "pulsar.topic_subscription_delayed",
   408  		Type:  module.Stacked,
   409  		Opts:  Opts{StoreFirst: true},
   410  	}
   411  	topicSubsMsgRateRedeliverChart = Chart{
   412  		ID:    "topic_subscription_msg_rate_redeliver_namespace_%s",
   413  		Title: "Topic Subscriptions Redelivered Message Rate",
   414  		Units: "messages/s",
   415  		Fam:   "ns %s",
   416  		Ctx:   "pulsar.topic_subscription_msg_rate_redeliver",
   417  		Type:  module.Stacked,
   418  		Opts:  Opts{StoreFirst: true},
   419  	}
   420  	topicSubsBlockedOnUnackedMsgChart = Chart{
   421  		ID:    "topic_subscription_blocked_on_unacked_messages_namespace_%s",
   422  		Title: "Topic Subscriptions Blocked On Unacked Messages",
   423  		Units: "blocked subscriptions",
   424  		Fam:   "ns %s",
   425  		Ctx:   "pulsar.topic_subscription_blocked_on_unacked_messages",
   426  		Type:  module.Stacked,
   427  		Opts:  Opts{StoreFirst: true},
   428  	}
   429  	topicReplicationRateInChart = Chart{
   430  		ID:    "topic_replication_rate_in_namespace_%s",
   431  		Title: "Topic Replication Rate From Remote Cluster",
   432  		Units: "messages/s",
   433  		Fam:   "ns %s",
   434  		Ctx:   "pulsar.topic_replication_rate_in",
   435  		Type:  module.Stacked,
   436  		Opts:  Opts{StoreFirst: true},
   437  	}
   438  	topicReplicationRateOutChart = Chart{
   439  		ID:    "replication_rate_out_namespace_%s",
   440  		Title: "Topic Replication Rate To Remote Cluster",
   441  		Units: "messages/s",
   442  		Fam:   "ns %s",
   443  		Ctx:   "pulsar.topic_replication_rate_out",
   444  		Type:  module.Stacked,
   445  		Opts:  Opts{StoreFirst: true},
   446  	}
   447  	topicReplicationThroughputRateInChart = Chart{
   448  		ID:    "topic_replication_throughput_rate_in_namespace_%s",
   449  		Title: "Topic Replication Throughput Rate From Remote Cluster",
   450  		Units: "KiB/s",
   451  		Fam:   "ns %s",
   452  		Ctx:   "pulsar.topic_replication_throughput_rate_in",
   453  		Type:  module.Stacked,
   454  		Opts:  Opts{StoreFirst: true},
   455  	}
   456  	topicReplicationThroughputRateOutChart = Chart{
   457  		ID:    "topic_replication_throughput_rate_out_namespace_%s",
   458  		Title: "Topic Replication Throughput Rate To Remote Cluster",
   459  		Units: "KiB/s",
   460  		Fam:   "ns %s",
   461  		Ctx:   "pulsar.topic_replication_throughput_rate_out",
   462  		Type:  module.Stacked,
   463  		Opts:  Opts{StoreFirst: true},
   464  	}
   465  	topicReplicationBacklogChart = Chart{
   466  		ID:    "topic_replication_backlog_namespace_%s",
   467  		Title: "Topic Replication Backlog",
   468  		Units: "messages",
   469  		Fam:   "ns %s",
   470  		Ctx:   "pulsar.topic_replication_backlog",
   471  		Type:  module.Stacked,
   472  		Opts:  Opts{StoreFirst: true},
   473  	}
   474  )
   475  
   476  func (p *Pulsar) adjustCharts(pms prometheus.Series) {
   477  	if pms := pms.FindByName(metricPulsarStorageReadRate); pms.Len() == 0 || pms[0].Labels.Get("namespace") == "" {
   478  		p.removeSummaryChart(sumStorageOperationsRateChart.ID)
   479  		p.removeNamespaceChart(nsStorageOperationsChart.ID)
   480  		p.removeNamespaceChart(topicStorageReadRateChart.ID)
   481  		p.removeNamespaceChart(topicStorageWriteRateChart.ID)
   482  		delete(p.topicChartsMapping, topicStorageReadRateChart.ID)
   483  		delete(p.topicChartsMapping, topicStorageWriteRateChart.ID)
   484  	}
   485  	if pms.FindByName(metricPulsarSubscriptionMsgRateRedeliver).Len() == 0 {
   486  		p.removeSummaryChart(sumSubsMsgRateRedeliverChart.ID)
   487  		p.removeSummaryChart(sumSubsBlockedOnUnackedMsgChart.ID)
   488  		p.removeNamespaceChart(nsSubsMsgRateRedeliverChart.ID)
   489  		p.removeNamespaceChart(nsSubsBlockedOnUnackedMsgChart.ID)
   490  		p.removeNamespaceChart(topicSubsMsgRateRedeliverChart.ID)
   491  		p.removeNamespaceChart(topicSubsBlockedOnUnackedMsgChart.ID)
   492  		delete(p.topicChartsMapping, topicSubsMsgRateRedeliverChart.ID)
   493  		delete(p.topicChartsMapping, topicSubsBlockedOnUnackedMsgChart.ID)
   494  	}
   495  	if pms.FindByName(metricPulsarReplicationBacklog).Len() == 0 {
   496  		p.removeSummaryChart(sumReplicationRateChart.ID)
   497  		p.removeSummaryChart(sumReplicationThroughputRateChart.ID)
   498  		p.removeSummaryChart(sumReplicationBacklogChart.ID)
   499  		p.removeNamespaceChart(nsReplicationRateChart.ID)
   500  		p.removeNamespaceChart(nsReplicationThroughputChart.ID)
   501  		p.removeNamespaceChart(nsReplicationBacklogChart.ID)
   502  		p.removeNamespaceChart(topicReplicationRateInChart.ID)
   503  		p.removeNamespaceChart(topicReplicationRateOutChart.ID)
   504  		p.removeNamespaceChart(topicReplicationThroughputRateInChart.ID)
   505  		p.removeNamespaceChart(topicReplicationThroughputRateOutChart.ID)
   506  		p.removeNamespaceChart(topicReplicationBacklogChart.ID)
   507  		delete(p.topicChartsMapping, topicReplicationRateInChart.ID)
   508  		delete(p.topicChartsMapping, topicReplicationRateOutChart.ID)
   509  		delete(p.topicChartsMapping, topicReplicationThroughputRateInChart.ID)
   510  		delete(p.topicChartsMapping, topicReplicationThroughputRateOutChart.ID)
   511  		delete(p.topicChartsMapping, topicReplicationBacklogChart.ID)
   512  	}
   513  }
   514  
   515  func (p *Pulsar) removeSummaryChart(chartID string) {
   516  	if err := p.Charts().Remove(chartID); err != nil {
   517  		p.Warning(err)
   518  	}
   519  }
   520  
   521  func (p *Pulsar) removeNamespaceChart(chartID string) {
   522  	if err := p.nsCharts.Remove(chartID); err != nil {
   523  		p.Warning(err)
   524  	}
   525  }
   526  
   527  func (p *Pulsar) updateCharts() {
   528  	// NOTE: order is important
   529  	for ns := range p.curCache.namespaces {
   530  		if !p.cache.namespaces[ns] {
   531  			p.cache.namespaces[ns] = true
   532  			p.addNamespaceCharts(ns)
   533  		}
   534  	}
   535  	for top := range p.curCache.topics {
   536  		if !p.cache.topics[top] {
   537  			p.cache.topics[top] = true
   538  			p.addTopicToCharts(top)
   539  		}
   540  	}
   541  	for top := range p.cache.topics {
   542  		if p.curCache.topics[top] {
   543  			continue
   544  		}
   545  		delete(p.cache.topics, top)
   546  		p.removeTopicFromCharts(top)
   547  	}
   548  	for ns := range p.cache.namespaces {
   549  		if p.curCache.namespaces[ns] {
   550  			continue
   551  		}
   552  		delete(p.cache.namespaces, ns)
   553  		p.removeNamespaceFromCharts(ns)
   554  	}
   555  }
   556  
   557  func (p *Pulsar) addNamespaceCharts(ns namespace) {
   558  	charts := p.nsCharts.Copy()
   559  	for _, chart := range *charts {
   560  		chart.ID = fmt.Sprintf(chart.ID, ns.name)
   561  		chart.Fam = fmt.Sprintf(chart.Fam, ns.name)
   562  		for _, dim := range chart.Dims {
   563  			dim.ID = fmt.Sprintf(dim.ID, ns.name)
   564  		}
   565  	}
   566  	if err := p.Charts().Add(*charts...); err != nil {
   567  		p.Warning(err)
   568  	}
   569  }
   570  
   571  func (p *Pulsar) removeNamespaceFromCharts(ns namespace) {
   572  	for _, chart := range *p.nsCharts {
   573  		id := fmt.Sprintf(chart.ID, ns.name)
   574  		if chart = p.Charts().Get(id); chart != nil {
   575  			chart.MarkRemove()
   576  		} else {
   577  			p.Warningf("could not remove namespace chart '%s'", id)
   578  		}
   579  	}
   580  }
   581  
   582  func (p *Pulsar) addTopicToCharts(top topic) {
   583  	for id, metric := range p.topicChartsMapping {
   584  		id = fmt.Sprintf(id, top.namespace)
   585  		chart := p.Charts().Get(id)
   586  		if chart == nil {
   587  			p.Warningf("could not add topic '%s' to chart '%s': chart not found", top.name, id)
   588  			continue
   589  		}
   590  
   591  		dim := Dim{ID: metric + "_" + top.name, Name: extractTopicName(top)}
   592  		switch metric {
   593  		case metricPulsarThroughputIn,
   594  			metricPulsarThroughputOut,
   595  			metricPulsarReplicationThroughputIn,
   596  			metricPulsarReplicationThroughputOut:
   597  			dim.Div = 1024 * 1000
   598  		case metricPulsarRateIn,
   599  			metricPulsarRateOut,
   600  			metricPulsarStorageWriteRate,
   601  			metricPulsarStorageReadRate,
   602  			metricPulsarSubscriptionMsgRateRedeliver,
   603  			metricPulsarReplicationRateIn,
   604  			metricPulsarReplicationRateOut:
   605  			dim.Div = 1000
   606  		case metricPulsarStorageSize:
   607  			dim.Div = 1024
   608  		}
   609  
   610  		if err := chart.AddDim(&dim); err != nil {
   611  			p.Warning(err)
   612  		}
   613  		chart.MarkNotCreated()
   614  	}
   615  }
   616  
   617  func (p *Pulsar) removeTopicFromCharts(top topic) {
   618  	for id, metric := range p.topicChartsMapping {
   619  		id = fmt.Sprintf(id, top.namespace)
   620  		chart := p.Charts().Get(id)
   621  		if chart == nil {
   622  			p.Warningf("could not remove topic '%s' from chart '%s': chart not found", top.name, id)
   623  			continue
   624  		}
   625  
   626  		if err := chart.MarkDimRemove(metric+"_"+top.name, true); err != nil {
   627  			p.Warning(err)
   628  		}
   629  		chart.MarkNotCreated()
   630  	}
   631  }
   632  
   633  func topicChartsMapping() map[string]string {
   634  	return map[string]string{
   635  		topicSubscriptionsChart.ID:                metricPulsarSubscriptionsCount,
   636  		topicProducersChart.ID:                    metricPulsarProducersCount,
   637  		topicConsumersChart.ID:                    metricPulsarConsumersCount,
   638  		topicMessagesRateInChart.ID:               metricPulsarRateIn,
   639  		topicMessagesRateOutChart.ID:              metricPulsarRateOut,
   640  		topicThroughputRateInChart.ID:             metricPulsarThroughputIn,
   641  		topicThroughputRateOutChart.ID:            metricPulsarThroughputOut,
   642  		topicStorageSizeChart.ID:                  metricPulsarStorageSize,
   643  		topicStorageReadRateChart.ID:              metricPulsarStorageReadRate,
   644  		topicStorageWriteRateChart.ID:             metricPulsarStorageWriteRate,
   645  		topicMsgBacklogSizeChart.ID:               metricPulsarMsgBacklog,
   646  		topicSubsDelayedChart.ID:                  metricPulsarSubscriptionDelayed,
   647  		topicSubsMsgRateRedeliverChart.ID:         metricPulsarSubscriptionMsgRateRedeliver,
   648  		topicSubsBlockedOnUnackedMsgChart.ID:      metricPulsarSubscriptionBlockedOnUnackedMessages,
   649  		topicReplicationRateInChart.ID:            metricPulsarReplicationRateIn,
   650  		topicReplicationRateOutChart.ID:           metricPulsarReplicationRateOut,
   651  		topicReplicationThroughputRateInChart.ID:  metricPulsarReplicationThroughputIn,
   652  		topicReplicationThroughputRateOutChart.ID: metricPulsarReplicationThroughputOut,
   653  		topicReplicationBacklogChart.ID:           metricPulsarReplicationBacklog,
   654  	}
   655  }
   656  
   657  func extractTopicName(top topic) string {
   658  	// persistent://sample/ns1/demo-1 => p:demo-1
   659  	if idx := strings.LastIndexByte(top.name, '/'); idx > 0 {
   660  		return top.name[:1] + ":" + top.name[idx+1:]
   661  	}
   662  	return top.name
   663  }