github.com/netdata/go.d.plugin@v0.58.1/modules/coredns/collect.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package coredns
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/blang/semver/v4"
    11  	"github.com/netdata/go.d.plugin/pkg/prometheus"
    12  	"github.com/netdata/go.d.plugin/pkg/stm"
    13  )
    14  
    15  const (
    16  	metricPanicCountTotal169orOlder         = "coredns_panic_count_total"
    17  	metricRequestCountTotal169orOlder       = "coredns_dns_request_count_total"
    18  	metricRequestTypeCountTotal169orOlder   = "coredns_dns_request_type_count_total"
    19  	metricResponseRcodeCountTotal169orOlder = "coredns_dns_response_rcode_count_total"
    20  
    21  	metricPanicCountTotal170orNewer         = "coredns_panics_total"
    22  	metricRequestCountTotal170orNewer       = "coredns_dns_requests_total"
    23  	metricRequestTypeCountTotal170orNewer   = "coredns_dns_requests_total"
    24  	metricResponseRcodeCountTotal170orNewer = "coredns_dns_responses_total"
    25  )
    26  
    27  var (
    28  	empty                  = ""
    29  	dropped                = "dropped"
    30  	emptyServerReplaceName = "empty"
    31  	rootZoneReplaceName    = "root"
    32  	version169             = semver.MustParse("1.6.9")
    33  )
    34  
    35  type requestMetricsNames struct {
    36  	panicCountTotal string
    37  	// true for all metrics below:
    38  	// - if none of server block matches 'server' tag is "", empty server has only one zone - dropped.
    39  	//   example:
    40  	//   coredns_dns_requests_total{family="1",proto="udp",server="",zone="dropped"} 1 for
    41  	// - dropped requests are added to both dropped and corresponding zone
    42  	//   example:
    43  	//   coredns_dns_requests_total{family="1",proto="udp",server="dns://:53",zone="dropped"} 2
    44  	//   coredns_dns_requests_total{family="1",proto="udp",server="dns://:53",zone="ya.ru."} 2
    45  	requestCountTotal       string
    46  	requestTypeCountTotal   string
    47  	responseRcodeCountTotal string
    48  }
    49  
    50  func (cd *CoreDNS) collect() (map[string]int64, error) {
    51  	raw, err := cd.prom.ScrapeSeries()
    52  
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	mx := newMetrics()
    58  
    59  	// some metric names are different depending on the version
    60  	// update them once
    61  	if !cd.skipVersionCheck {
    62  		cd.updateVersionDependentMetrics(raw)
    63  		cd.skipVersionCheck = true
    64  	}
    65  
    66  	//we can only get these metrics if we know the server version
    67  	if cd.version == nil {
    68  		return nil, errors.New("unable to determine server version")
    69  	}
    70  
    71  	cd.collectPanic(mx, raw)
    72  	cd.collectSummaryRequests(mx, raw)
    73  	cd.collectSummaryRequestsPerType(mx, raw)
    74  	cd.collectSummaryResponsesPerRcode(mx, raw)
    75  
    76  	if cd.perServerMatcher != nil {
    77  		cd.collectPerServerRequests(mx, raw)
    78  		//cd.collectPerServerRequestsDuration(mx, raw)
    79  		cd.collectPerServerRequestPerType(mx, raw)
    80  		cd.collectPerServerResponsePerRcode(mx, raw)
    81  	}
    82  
    83  	if cd.perZoneMatcher != nil {
    84  		cd.collectPerZoneRequests(mx, raw)
    85  		//cd.collectPerZoneRequestsDuration(mx, raw)
    86  		cd.collectPerZoneRequestsPerType(mx, raw)
    87  		cd.collectPerZoneResponsesPerRcode(mx, raw)
    88  	}
    89  
    90  	return stm.ToMap(mx), nil
    91  }
    92  
    93  func (cd *CoreDNS) updateVersionDependentMetrics(raw prometheus.Series) {
    94  	version := cd.parseVersion(raw)
    95  	if version == nil {
    96  		return
    97  	}
    98  	cd.version = version
    99  	if cd.version.LTE(version169) {
   100  		cd.metricNames.panicCountTotal = metricPanicCountTotal169orOlder
   101  		cd.metricNames.requestCountTotal = metricRequestCountTotal169orOlder
   102  		cd.metricNames.requestTypeCountTotal = metricRequestTypeCountTotal169orOlder
   103  		cd.metricNames.responseRcodeCountTotal = metricResponseRcodeCountTotal169orOlder
   104  	} else {
   105  		cd.metricNames.panicCountTotal = metricPanicCountTotal170orNewer
   106  		cd.metricNames.requestCountTotal = metricRequestCountTotal170orNewer
   107  		cd.metricNames.requestTypeCountTotal = metricRequestTypeCountTotal170orNewer
   108  		cd.metricNames.responseRcodeCountTotal = metricResponseRcodeCountTotal170orNewer
   109  	}
   110  }
   111  
   112  func (cd *CoreDNS) parseVersion(raw prometheus.Series) *semver.Version {
   113  	var versionStr string
   114  	for _, metric := range raw.FindByName("coredns_build_info") {
   115  		versionStr = metric.Labels.Get("version")
   116  	}
   117  	if versionStr == "" {
   118  		cd.Error("cannot find version string in metrics")
   119  		return nil
   120  	}
   121  
   122  	version, err := semver.Make(versionStr)
   123  	if err != nil {
   124  		cd.Errorf("failed to find server version: %v", err)
   125  		return nil
   126  	}
   127  	return &version
   128  }
   129  
   130  func (cd *CoreDNS) collectPanic(mx *metrics, raw prometheus.Series) {
   131  	mx.Panic.Set(raw.FindByName(cd.metricNames.panicCountTotal).Max())
   132  }
   133  
   134  func (cd *CoreDNS) collectSummaryRequests(mx *metrics, raw prometheus.Series) {
   135  	for _, metric := range raw.FindByName(cd.metricNames.requestCountTotal) {
   136  		var (
   137  			family = metric.Labels.Get("family")
   138  			proto  = metric.Labels.Get("proto")
   139  			server = metric.Labels.Get("server")
   140  			zone   = metric.Labels.Get("zone")
   141  			value  = metric.Value
   142  		)
   143  
   144  		if family == empty || proto == empty || zone == empty {
   145  			continue
   146  		}
   147  
   148  		if server == empty {
   149  			mx.NoZoneDropped.Add(value)
   150  		}
   151  
   152  		setRequestPerStatus(&mx.Summary.Request, value, server, zone)
   153  
   154  		if zone == dropped && server != empty {
   155  			continue
   156  		}
   157  
   158  		mx.Summary.Request.Total.Add(value)
   159  		setRequestPerIPFamily(&mx.Summary.Request, value, family)
   160  		setRequestPerProto(&mx.Summary.Request, value, proto)
   161  	}
   162  }
   163  
   164  //func (cd *CoreDNS) collectSummaryRequestsDuration(mx *metrics, raw prometheus.Series) {
   165  //	for _, metric := range raw.FindByName(metricRequestDurationSecondsBucket) {
   166  //		var (
   167  //			server = metric.Labels.Get("server")
   168  //			zone   = metric.Labels.Get("zone")
   169  //			le     = metric.Labels.Get("le")
   170  //			value  = metric.Value
   171  //		)
   172  //
   173  //		if zone == empty || zone == dropped && server != empty || le == empty {
   174  //			continue
   175  //		}
   176  //
   177  //		setRequestDuration(&mx.Summary.Request, value, le)
   178  //	}
   179  //	processRequestDuration(&mx.Summary.Request)
   180  //}
   181  
   182  func (cd *CoreDNS) collectSummaryRequestsPerType(mx *metrics, raw prometheus.Series) {
   183  	for _, metric := range raw.FindByName(cd.metricNames.requestTypeCountTotal) {
   184  		var (
   185  			server = metric.Labels.Get("server")
   186  			typ    = metric.Labels.Get("type")
   187  			zone   = metric.Labels.Get("zone")
   188  			value  = metric.Value
   189  		)
   190  
   191  		if typ == empty || zone == empty || zone == dropped && server != empty {
   192  			continue
   193  		}
   194  
   195  		setRequestPerType(&mx.Summary.Request, value, typ)
   196  	}
   197  }
   198  
   199  func (cd *CoreDNS) collectSummaryResponsesPerRcode(mx *metrics, raw prometheus.Series) {
   200  	for _, metric := range raw.FindByName(cd.metricNames.responseRcodeCountTotal) {
   201  		var (
   202  			rcode  = metric.Labels.Get("rcode")
   203  			server = metric.Labels.Get("server")
   204  			zone   = metric.Labels.Get("zone")
   205  			value  = metric.Value
   206  		)
   207  
   208  		if rcode == empty || zone == empty || zone == dropped && server != empty {
   209  			continue
   210  		}
   211  
   212  		setResponsePerRcode(&mx.Summary.Response, value, rcode)
   213  	}
   214  }
   215  
   216  // Per Server
   217  
   218  func (cd *CoreDNS) collectPerServerRequests(mx *metrics, raw prometheus.Series) {
   219  	for _, metric := range raw.FindByName(cd.metricNames.requestCountTotal) {
   220  		var (
   221  			family = metric.Labels.Get("family")
   222  			proto  = metric.Labels.Get("proto")
   223  			server = metric.Labels.Get("server")
   224  			zone   = metric.Labels.Get("zone")
   225  			value  = metric.Value
   226  		)
   227  
   228  		if family == empty || proto == empty || zone == empty {
   229  			continue
   230  		}
   231  
   232  		if !cd.perServerMatcher.MatchString(server) {
   233  			continue
   234  		}
   235  
   236  		if server == empty {
   237  			server = emptyServerReplaceName
   238  		}
   239  
   240  		if !cd.collectedServers[server] {
   241  			cd.addNewServerCharts(server)
   242  			cd.collectedServers[server] = true
   243  		}
   244  
   245  		if _, ok := mx.PerServer[server]; !ok {
   246  			mx.PerServer[server] = &requestResponse{}
   247  		}
   248  
   249  		srv := mx.PerServer[server]
   250  
   251  		setRequestPerStatus(&srv.Request, value, server, zone)
   252  
   253  		if zone == dropped && server != emptyServerReplaceName {
   254  			continue
   255  		}
   256  
   257  		srv.Request.Total.Add(value)
   258  		setRequestPerIPFamily(&srv.Request, value, family)
   259  		setRequestPerProto(&srv.Request, value, proto)
   260  	}
   261  }
   262  
   263  //func (cd *CoreDNS) collectPerServerRequestsDuration(mx *metrics, raw prometheus.Series) {
   264  //	for _, metric := range raw.FindByName(metricRequestDurationSecondsBucket) {
   265  //		var (
   266  //			server = metric.Labels.Get("server")
   267  //			zone   = metric.Labels.Get("zone")
   268  //			le     = metric.Labels.Get("le")
   269  //			value  = metric.Value
   270  //		)
   271  //
   272  //		if zone == empty || zone == dropped && server != empty || le == empty {
   273  //			continue
   274  //		}
   275  //
   276  //		if !cd.perServerMatcher.MatchString(server) {
   277  //			continue
   278  //		}
   279  //
   280  //		if server == empty {
   281  //			server = emptyServerReplaceName
   282  //		}
   283  //
   284  //		if !cd.collectedServers[server] {
   285  //			cd.addNewServerCharts(server)
   286  //			cd.collectedServers[server] = true
   287  //		}
   288  //
   289  //		if _, ok := mx.PerServer[server]; !ok {
   290  //			mx.PerServer[server] = &requestResponse{}
   291  //		}
   292  //
   293  //		setRequestDuration(&mx.PerServer[server].Request, value, le)
   294  //	}
   295  //	for _, s := range mx.PerServer {
   296  //		processRequestDuration(&s.Request)
   297  //	}
   298  //}
   299  
   300  func (cd *CoreDNS) collectPerServerRequestPerType(mx *metrics, raw prometheus.Series) {
   301  	for _, metric := range raw.FindByName(cd.metricNames.requestTypeCountTotal) {
   302  		var (
   303  			server = metric.Labels.Get("server")
   304  			typ    = metric.Labels.Get("type")
   305  			zone   = metric.Labels.Get("zone")
   306  			value  = metric.Value
   307  		)
   308  
   309  		if typ == empty || zone == empty || zone == dropped && server != empty {
   310  			continue
   311  		}
   312  
   313  		if !cd.perServerMatcher.MatchString(server) {
   314  			continue
   315  		}
   316  
   317  		if server == empty {
   318  			server = emptyServerReplaceName
   319  		}
   320  
   321  		if !cd.collectedServers[server] {
   322  			cd.addNewServerCharts(server)
   323  			cd.collectedServers[server] = true
   324  		}
   325  
   326  		if _, ok := mx.PerServer[server]; !ok {
   327  			mx.PerServer[server] = &requestResponse{}
   328  		}
   329  
   330  		setRequestPerType(&mx.PerServer[server].Request, value, typ)
   331  	}
   332  }
   333  
   334  func (cd *CoreDNS) collectPerServerResponsePerRcode(mx *metrics, raw prometheus.Series) {
   335  	for _, metric := range raw.FindByName(cd.metricNames.responseRcodeCountTotal) {
   336  		var (
   337  			rcode  = metric.Labels.Get("rcode")
   338  			server = metric.Labels.Get("server")
   339  			zone   = metric.Labels.Get("zone")
   340  			value  = metric.Value
   341  		)
   342  
   343  		if rcode == empty || zone == empty || zone == dropped && server != empty {
   344  			continue
   345  		}
   346  
   347  		if !cd.perServerMatcher.MatchString(server) {
   348  			continue
   349  		}
   350  
   351  		if server == empty {
   352  			server = emptyServerReplaceName
   353  		}
   354  
   355  		if !cd.collectedServers[server] {
   356  			cd.addNewServerCharts(server)
   357  			cd.collectedServers[server] = true
   358  		}
   359  
   360  		if _, ok := mx.PerServer[server]; !ok {
   361  			mx.PerServer[server] = &requestResponse{}
   362  		}
   363  
   364  		setResponsePerRcode(&mx.PerServer[server].Response, value, rcode)
   365  	}
   366  }
   367  
   368  // Per Zone
   369  
   370  func (cd *CoreDNS) collectPerZoneRequests(mx *metrics, raw prometheus.Series) {
   371  	for _, metric := range raw.FindByName(cd.metricNames.requestCountTotal) {
   372  		var (
   373  			family = metric.Labels.Get("family")
   374  			proto  = metric.Labels.Get("proto")
   375  			zone   = metric.Labels.Get("zone")
   376  			value  = metric.Value
   377  		)
   378  
   379  		if family == empty || proto == empty || zone == empty {
   380  			continue
   381  		}
   382  
   383  		if !cd.perZoneMatcher.MatchString(zone) {
   384  			continue
   385  		}
   386  
   387  		if zone == "." {
   388  			zone = rootZoneReplaceName
   389  		}
   390  
   391  		if !cd.collectedZones[zone] {
   392  			cd.addNewZoneCharts(zone)
   393  			cd.collectedZones[zone] = true
   394  		}
   395  
   396  		if _, ok := mx.PerZone[zone]; !ok {
   397  			mx.PerZone[zone] = &requestResponse{}
   398  		}
   399  
   400  		zoneMX := mx.PerZone[zone]
   401  		zoneMX.Request.Total.Add(value)
   402  		setRequestPerIPFamily(&zoneMX.Request, value, family)
   403  		setRequestPerProto(&zoneMX.Request, value, proto)
   404  	}
   405  }
   406  
   407  //func (cd *CoreDNS) collectPerZoneRequestsDuration(mx *metrics, raw prometheus.Series) {
   408  //	for _, metric := range raw.FindByName(metricRequestDurationSecondsBucket) {
   409  //		var (
   410  //			zone  = metric.Labels.Get("zone")
   411  //			le    = metric.Labels.Get("le")
   412  //			value = metric.Value
   413  //		)
   414  //
   415  //		if zone == empty || le == empty {
   416  //			continue
   417  //		}
   418  //
   419  //		if !cd.perZoneMatcher.MatchString(zone) {
   420  //			continue
   421  //		}
   422  //
   423  //		if zone == "." {
   424  //			zone = rootZoneReplaceName
   425  //		}
   426  //
   427  //		if !cd.collectedZones[zone] {
   428  //			cd.addNewZoneCharts(zone)
   429  //			cd.collectedZones[zone] = true
   430  //		}
   431  //
   432  //		if _, ok := mx.PerZone[zone]; !ok {
   433  //			mx.PerZone[zone] = &requestResponse{}
   434  //		}
   435  //
   436  //		setRequestDuration(&mx.PerZone[zone].Request, value, le)
   437  //	}
   438  //	for _, s := range mx.PerZone {
   439  //		processRequestDuration(&s.Request)
   440  //	}
   441  //}
   442  
   443  func (cd *CoreDNS) collectPerZoneRequestsPerType(mx *metrics, raw prometheus.Series) {
   444  	for _, metric := range raw.FindByName(cd.metricNames.requestTypeCountTotal) {
   445  		var (
   446  			typ   = metric.Labels.Get("type")
   447  			zone  = metric.Labels.Get("zone")
   448  			value = metric.Value
   449  		)
   450  
   451  		if typ == empty || zone == empty {
   452  			continue
   453  		}
   454  
   455  		if !cd.perZoneMatcher.MatchString(zone) {
   456  			continue
   457  		}
   458  
   459  		if zone == "." {
   460  			zone = rootZoneReplaceName
   461  		}
   462  
   463  		if !cd.collectedZones[zone] {
   464  			cd.addNewZoneCharts(zone)
   465  			cd.collectedZones[zone] = true
   466  		}
   467  
   468  		if _, ok := mx.PerZone[zone]; !ok {
   469  			mx.PerZone[zone] = &requestResponse{}
   470  		}
   471  
   472  		setRequestPerType(&mx.PerZone[zone].Request, value, typ)
   473  	}
   474  }
   475  
   476  func (cd *CoreDNS) collectPerZoneResponsesPerRcode(mx *metrics, raw prometheus.Series) {
   477  	for _, metric := range raw.FindByName(cd.metricNames.responseRcodeCountTotal) {
   478  		var (
   479  			rcode = metric.Labels.Get("rcode")
   480  			zone  = metric.Labels.Get("zone")
   481  			value = metric.Value
   482  		)
   483  
   484  		if rcode == empty || zone == empty {
   485  			continue
   486  		}
   487  
   488  		if !cd.perZoneMatcher.MatchString(zone) {
   489  			continue
   490  		}
   491  
   492  		if zone == "." {
   493  			zone = rootZoneReplaceName
   494  		}
   495  
   496  		if !cd.collectedZones[zone] {
   497  			cd.addNewZoneCharts(zone)
   498  			cd.collectedZones[zone] = true
   499  		}
   500  
   501  		if _, ok := mx.PerZone[zone]; !ok {
   502  			mx.PerZone[zone] = &requestResponse{}
   503  		}
   504  
   505  		setResponsePerRcode(&mx.PerZone[zone].Response, value, rcode)
   506  	}
   507  }
   508  
   509  // ---
   510  
   511  func setRequestPerIPFamily(mx *request, value float64, family string) {
   512  	switch family {
   513  	case "1":
   514  		mx.PerIPFamily.IPv4.Add(value)
   515  	case "2":
   516  		mx.PerIPFamily.IPv6.Add(value)
   517  	}
   518  }
   519  
   520  func setRequestPerProto(mx *request, value float64, proto string) {
   521  	switch proto {
   522  	case "udp":
   523  		mx.PerProto.UDP.Add(value)
   524  	case "tcp":
   525  		mx.PerProto.TCP.Add(value)
   526  	}
   527  }
   528  
   529  func setRequestPerStatus(mx *request, value float64, server, zone string) {
   530  	switch zone {
   531  	default:
   532  		mx.PerStatus.Processed.Add(value)
   533  	case "dropped":
   534  		mx.PerStatus.Dropped.Add(value)
   535  		if server == empty || server == emptyServerReplaceName {
   536  			return
   537  		}
   538  		mx.PerStatus.Processed.Sub(value)
   539  	}
   540  }
   541  
   542  func setRequestPerType(mx *request, value float64, typ string) {
   543  	switch typ {
   544  	default:
   545  		mx.PerType.Other.Add(value)
   546  	case "A":
   547  		mx.PerType.A.Add(value)
   548  	case "AAAA":
   549  		mx.PerType.AAAA.Add(value)
   550  	case "MX":
   551  		mx.PerType.MX.Add(value)
   552  	case "SOA":
   553  		mx.PerType.SOA.Add(value)
   554  	case "CNAME":
   555  		mx.PerType.CNAME.Add(value)
   556  	case "PTR":
   557  		mx.PerType.PTR.Add(value)
   558  	case "TXT":
   559  		mx.PerType.TXT.Add(value)
   560  	case "NS":
   561  		mx.PerType.NS.Add(value)
   562  	case "DS":
   563  		mx.PerType.DS.Add(value)
   564  	case "DNSKEY":
   565  		mx.PerType.DNSKEY.Add(value)
   566  	case "RRSIG":
   567  		mx.PerType.RRSIG.Add(value)
   568  	case "NSEC":
   569  		mx.PerType.NSEC.Add(value)
   570  	case "NSEC3":
   571  		mx.PerType.NSEC3.Add(value)
   572  	case "IXFR":
   573  		mx.PerType.IXFR.Add(value)
   574  	case "ANY":
   575  		mx.PerType.ANY.Add(value)
   576  	}
   577  }
   578  
   579  func setResponsePerRcode(mx *response, value float64, rcode string) {
   580  	mx.Total.Add(value)
   581  
   582  	switch rcode {
   583  	default:
   584  		mx.PerRcode.Other.Add(value)
   585  	case "NOERROR":
   586  		mx.PerRcode.NOERROR.Add(value)
   587  	case "FORMERR":
   588  		mx.PerRcode.FORMERR.Add(value)
   589  	case "SERVFAIL":
   590  		mx.PerRcode.SERVFAIL.Add(value)
   591  	case "NXDOMAIN":
   592  		mx.PerRcode.NXDOMAIN.Add(value)
   593  	case "NOTIMP":
   594  		mx.PerRcode.NOTIMP.Add(value)
   595  	case "REFUSED":
   596  		mx.PerRcode.REFUSED.Add(value)
   597  	case "YXDOMAIN":
   598  		mx.PerRcode.YXDOMAIN.Add(value)
   599  	case "YXRRSET":
   600  		mx.PerRcode.YXRRSET.Add(value)
   601  	case "NXRRSET":
   602  		mx.PerRcode.NXRRSET.Add(value)
   603  	case "NOTAUTH":
   604  		mx.PerRcode.NOTAUTH.Add(value)
   605  	case "NOTZONE":
   606  		mx.PerRcode.NOTZONE.Add(value)
   607  	case "BADSIG":
   608  		mx.PerRcode.BADSIG.Add(value)
   609  	case "BADKEY":
   610  		mx.PerRcode.BADKEY.Add(value)
   611  	case "BADTIME":
   612  		mx.PerRcode.BADTIME.Add(value)
   613  	case "BADMODE":
   614  		mx.PerRcode.BADMODE.Add(value)
   615  	case "BADNAME":
   616  		mx.PerRcode.BADNAME.Add(value)
   617  	case "BADALG":
   618  		mx.PerRcode.BADALG.Add(value)
   619  	case "BADTRUNC":
   620  		mx.PerRcode.BADTRUNC.Add(value)
   621  	case "BADCOOKIE":
   622  		mx.PerRcode.BADCOOKIE.Add(value)
   623  	}
   624  }
   625  
   626  //func setRequestDuration(mx *request, value float64, le string) {
   627  //	switch le {
   628  //	case "0.00025":
   629  //		mx.Duration.LE000025.Add(value)
   630  //	case "0.0005":
   631  //		mx.Duration.LE00005.Add(value)
   632  //	case "0.001":
   633  //		mx.Duration.LE0001.Add(value)
   634  //	case "0.002":
   635  //		mx.Duration.LE0002.Add(value)
   636  //	case "0.004":
   637  //		mx.Duration.LE0004.Add(value)
   638  //	case "0.008":
   639  //		mx.Duration.LE0008.Add(value)
   640  //	case "0.016":
   641  //		mx.Duration.LE0016.Add(value)
   642  //	case "0.032":
   643  //		mx.Duration.LE0032.Add(value)
   644  //	case "0.064":
   645  //		mx.Duration.LE0064.Add(value)
   646  //	case "0.128":
   647  //		mx.Duration.LE0128.Add(value)
   648  //	case "0.256":
   649  //		mx.Duration.LE0256.Add(value)
   650  //	case "0.512":
   651  //		mx.Duration.LE0512.Add(value)
   652  //	case "1.024":
   653  //		mx.Duration.LE1024.Add(value)
   654  //	case "2.048":
   655  //		mx.Duration.LE2048.Add(value)
   656  //	case "4.096":
   657  //		mx.Duration.LE4096.Add(value)
   658  //	case "8.192":
   659  //		mx.Duration.LE8192.Add(value)
   660  //	case "+Inf":
   661  //		mx.Duration.LEInf.Add(value)
   662  //	}
   663  //}
   664  
   665  //func processRequestDuration(mx *request) {
   666  //	mx.Duration.LEInf.Sub(mx.Duration.LE8192.Value())
   667  //	mx.Duration.LE8192.Sub(mx.Duration.LE4096.Value())
   668  //	mx.Duration.LE4096.Sub(mx.Duration.LE2048.Value())
   669  //	mx.Duration.LE2048.Sub(mx.Duration.LE1024.Value())
   670  //	mx.Duration.LE1024.Sub(mx.Duration.LE0512.Value())
   671  //	mx.Duration.LE0512.Sub(mx.Duration.LE0256.Value())
   672  //	mx.Duration.LE0256.Sub(mx.Duration.LE0128.Value())
   673  //	mx.Duration.LE0128.Sub(mx.Duration.LE0064.Value())
   674  //	mx.Duration.LE0064.Sub(mx.Duration.LE0032.Value())
   675  //	mx.Duration.LE0032.Sub(mx.Duration.LE0016.Value())
   676  //	mx.Duration.LE0016.Sub(mx.Duration.LE0008.Value())
   677  //	mx.Duration.LE0008.Sub(mx.Duration.LE0004.Value())
   678  //	mx.Duration.LE0004.Sub(mx.Duration.LE0002.Value())
   679  //	mx.Duration.LE0002.Sub(mx.Duration.LE0001.Value())
   680  //	mx.Duration.LE0001.Sub(mx.Duration.LE00005.Value())
   681  //	mx.Duration.LE00005.Sub(mx.Duration.LE000025.Value())
   682  //}
   683  
   684  // ---
   685  
   686  func (cd *CoreDNS) addNewServerCharts(name string) {
   687  	charts := serverCharts.Copy()
   688  	for _, chart := range *charts {
   689  		chart.ID = fmt.Sprintf(chart.ID, "server", name)
   690  		chart.Title = fmt.Sprintf(chart.Title, "Server", name)
   691  		chart.Fam = fmt.Sprintf(chart.Fam, "server", name)
   692  
   693  		for _, dim := range chart.Dims {
   694  			dim.ID = fmt.Sprintf(dim.ID, name)
   695  		}
   696  	}
   697  	_ = cd.charts.Add(*charts...)
   698  }
   699  
   700  func (cd *CoreDNS) addNewZoneCharts(name string) {
   701  	charts := zoneCharts.Copy()
   702  	for _, chart := range *charts {
   703  		chart.ID = fmt.Sprintf(chart.ID, "zone", name)
   704  		chart.Title = fmt.Sprintf(chart.Title, "Zone", name)
   705  		chart.Fam = fmt.Sprintf(chart.Fam, "zone", name)
   706  		chart.Ctx = strings.Replace(chart.Ctx, "coredns.server_", "coredns.zone_", 1)
   707  
   708  		for _, dim := range chart.Dims {
   709  			dim.ID = fmt.Sprintf(dim.ID, name)
   710  		}
   711  	}
   712  	_ = cd.charts.Add(*charts...)
   713  }