You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by mi...@apache.org on 2016/11/07 22:23:42 UTC
[21/26] incubator-trafficcontrol git commit: merge master
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/config/config.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/config/config.go b/traffic_monitor/experimental/traffic_monitor/config/config.go
index 1ca4b80..ce24883 100644
--- a/traffic_monitor/experimental/traffic_monitor/config/config.go
+++ b/traffic_monitor/experimental/traffic_monitor/config/config.go
@@ -1,22 +1,49 @@
package config
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"encoding/json"
"io/ioutil"
"time"
)
+// LogLocation is a location to log to. This may be stdout, stderr, null (/dev/null), or a valid file path.
type LogLocation string
-const LogLocationStdout = "stdout"
-const LogLocationStderr = "stderr"
-const LogLocationNull = "null"
+const (
+ // LogLocationStdout indicates the stdout IO stream
+ LogLocationStdout = "stdout"
+ // LogLocationStderr indicates the stderr IO stream
+ LogLocationStderr = "stderr"
+ // LogLocationNull indicates the null IO stream (/dev/null)
+ LogLocationNull = "null"
+)
+// Config is the configuration for the application. It includes myriad data, such as polling intervals and log locations.
type Config struct {
CacheHealthPollingInterval time.Duration `json:"-"`
CacheStatPollingInterval time.Duration `json:"-"`
MonitorConfigPollingInterval time.Duration `json:"-"`
- HttpTimeout time.Duration `json:"-"`
+ HTTPTimeout time.Duration `json:"-"`
PeerPollingInterval time.Duration `json:"-"`
MaxEvents uint64 `json:"max_events"`
MaxStatHistory uint64 `json:"max_stat_history"`
@@ -27,13 +54,17 @@ type Config struct {
LogLocationWarning string `json:"log_location_warning"`
LogLocationInfo string `json:"log_location_info"`
LogLocationDebug string `json:"log_location_debug"`
+ ServeReadTimeout time.Duration `json:"-"`
+ ServeWriteTimeout time.Duration `json:"-"`
+ HealthToStatRatio uint64 `json:"health_to_stat_ratio"`
}
+// DefaultConfig is the default configuration for the application, if no configuration file is given, or if a given config setting doesn't exist in the config file.
var DefaultConfig = Config{
CacheHealthPollingInterval: 6 * time.Second,
CacheStatPollingInterval: 6 * time.Second,
MonitorConfigPollingInterval: 5 * time.Second,
- HttpTimeout: 2 * time.Second,
+ HTTPTimeout: 2 * time.Second,
PeerPollingInterval: 5 * time.Second,
MaxEvents: 200,
MaxStatHistory: 5,
@@ -44,6 +75,9 @@ var DefaultConfig = Config{
LogLocationWarning: LogLocationStdout,
LogLocationInfo: LogLocationNull,
LogLocationDebug: LogLocationNull,
+ ServeReadTimeout: 10 * time.Second,
+ ServeWriteTimeout: 10 * time.Second,
+ HealthToStatRatio: 4,
}
// MarshalJSON marshals custom millisecond durations. Aliasing inspired by http://choly.ca/post/go-json-marshalling/
@@ -53,16 +87,18 @@ func (c *Config) MarshalJSON() ([]byte, error) {
CacheHealthPollingIntervalMs uint64 `json:"cache_health_polling_interval_ms"`
CacheStatPollingIntervalMs uint64 `json:"cache_stat_polling_interval_ms"`
MonitorConfigPollingIntervalMs uint64 `json:"monitor_config_polling_interval_ms"`
- HttpTimeoutMs uint64 `json:"http_timeout_ms"`
+ HTTPTimeoutMS uint64 `json:"http_timeout_ms"`
PeerPollingIntervalMs uint64 `json:"peer_polling_interval_ms"`
HealthFlushIntervalMs uint64 `json:"health_flush_interval_ms"`
StatFlushIntervalMs uint64 `json:"stat_flush_interval_ms"`
+ ServeReadTimeoutMs uint64 `json:"serve_read_timeout_ms"`
+ ServeWriteTimeoutMs uint64 `json:"serve_write_timeout_ms"`
*Alias
}{
CacheHealthPollingIntervalMs: uint64(c.CacheHealthPollingInterval / time.Millisecond),
CacheStatPollingIntervalMs: uint64(c.CacheStatPollingInterval / time.Millisecond),
MonitorConfigPollingIntervalMs: uint64(c.MonitorConfigPollingInterval / time.Millisecond),
- HttpTimeoutMs: uint64(c.HttpTimeout / time.Millisecond),
+ HTTPTimeoutMS: uint64(c.HTTPTimeout / time.Millisecond),
PeerPollingIntervalMs: uint64(c.PeerPollingInterval / time.Millisecond),
HealthFlushIntervalMs: uint64(c.HealthFlushInterval / time.Millisecond),
StatFlushIntervalMs: uint64(c.StatFlushInterval / time.Millisecond),
@@ -70,16 +106,19 @@ func (c *Config) MarshalJSON() ([]byte, error) {
})
}
+// UnmarshalJSON populates this config object from given JSON bytes.
func (c *Config) UnmarshalJSON(data []byte) error {
type Alias Config
aux := &struct {
CacheHealthPollingIntervalMs *uint64 `json:"cache_health_polling_interval_ms"`
CacheStatPollingIntervalMs *uint64 `json:"cache_stat_polling_interval_ms"`
MonitorConfigPollingIntervalMs *uint64 `json:"monitor_config_polling_interval_ms"`
- HttpTimeoutMs *uint64 `json:"http_timeout_ms"`
+ HTTPTimeoutMS *uint64 `json:"http_timeout_ms"`
PeerPollingIntervalMs *uint64 `json:"peer_polling_interval_ms"`
HealthFlushIntervalMs *uint64 `json:"health_flush_interval_ms"`
StatFlushIntervalMs *uint64 `json:"stat_flush_interval_ms"`
+ ServeReadTimeoutMs *uint64 `json:"serve_read_timeout_ms"`
+ ServeWriteTimeoutMs *uint64 `json:"serve_write_timeout_ms"`
*Alias
}{
Alias: (*Alias)(c),
@@ -97,8 +136,8 @@ func (c *Config) UnmarshalJSON(data []byte) error {
if aux.MonitorConfigPollingIntervalMs != nil {
c.MonitorConfigPollingInterval = time.Duration(*aux.MonitorConfigPollingIntervalMs) * time.Millisecond
}
- if aux.HttpTimeoutMs != nil {
- c.HttpTimeout = time.Duration(*aux.HttpTimeoutMs) * time.Millisecond
+ if aux.HTTPTimeoutMS != nil {
+ c.HTTPTimeout = time.Duration(*aux.HTTPTimeoutMS) * time.Millisecond
}
if aux.PeerPollingIntervalMs != nil {
c.PeerPollingInterval = time.Duration(*aux.PeerPollingIntervalMs) * time.Millisecond
@@ -109,6 +148,12 @@ func (c *Config) UnmarshalJSON(data []byte) error {
if aux.StatFlushIntervalMs != nil {
c.StatFlushInterval = time.Duration(*aux.StatFlushIntervalMs) * time.Millisecond
}
+ if aux.ServeReadTimeoutMs != nil {
+ c.ServeReadTimeout = time.Duration(*aux.ServeReadTimeoutMs) * time.Millisecond
+ }
+ if aux.ServeWriteTimeoutMs != nil {
+ c.ServeWriteTimeout = time.Duration(*aux.ServeWriteTimeoutMs) * time.Millisecond
+ }
return nil
}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go b/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
index 8b72163..ebd883f 100644
--- a/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
+++ b/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
@@ -1,14 +1,34 @@
package deliveryservice
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"fmt"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/common/log"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/cache"
- dsdata "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/enum"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/http_server"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/peer"
- todata "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
+ dsdata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/srvhttp"
+ todata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
"net/url"
"strconv"
"time"
@@ -16,24 +36,30 @@ import (
// TODO remove 'ds' and 'stat' from names
+// Stats is the JSON-serialisable representation of delivery service Stats. It maps delivery service names to individual stat objects.
// TODO remove DeliveryService and set type to the map directly, or add other members
type Stats struct {
DeliveryService map[enum.DeliveryServiceName]dsdata.Stat `json:"deliveryService"`
+ Time time.Time `json:"-"`
}
-func (a Stats) Copy() Stats {
+// Copy performs a deep copy of this Stats object.
+func (s Stats) Copy() Stats {
b := NewStats()
- for k, v := range a.DeliveryService {
+ for k, v := range s.DeliveryService {
b.DeliveryService[k] = v.Copy()
}
+ b.Time = s.Time
return b
}
-func (a Stats) Get(name enum.DeliveryServiceName) (dsdata.StatReadonly, bool) {
- ds, ok := a.DeliveryService[name]
+// Get returns the stats for the given delivery service, and whether it exists.
+func (s Stats) Get(name enum.DeliveryServiceName) (dsdata.StatReadonly, bool) {
+ ds, ok := s.DeliveryService[name]
return ds, ok
}
+// NewStats creates a new Stats object, initializing any pointer members.
// TODO rename to just 'New'?
func NewStats() Stats {
return Stats{DeliveryService: map[enum.DeliveryServiceName]dsdata.Stat{}}
@@ -59,7 +85,7 @@ func addAvailableData(dsStats Stats, crStates peer.Crstates, serverCachegroups m
log.Warnf("CreateStats not adding availability data for '%s': not found in DeliveryServices\n", cache)
continue
}
- cacheType, ok := serverTypes[enum.CacheName(cache)]
+ cacheType, ok := serverTypes[cache]
if !ok {
log.Warnf("CreateStats not adding availability data for '%s': not found in Server Types\n", cache)
continue
@@ -71,19 +97,20 @@ func addAvailableData(dsStats Stats, crStates peer.Crstates, serverCachegroups m
continue
}
- stat, ok := dsStats.DeliveryService[enum.DeliveryServiceName(deliveryService)]
+ stat, ok := dsStats.DeliveryService[deliveryService]
if !ok {
log.Warnf("CreateStats not adding availability data for '%s': not found in Stats\n", cache)
continue // TODO log warning? Error?
}
if available.IsAvailable {
- // c.IsAvailable.Value
stat.CommonStats.IsAvailable.Value = true
+ // TODO fix to be whether the Delivery Service has exceeded max kbps defined in Traffic Ops in `/health/cdn-name`?
+ stat.CommonStats.IsHealthy.Value = true
stat.CommonStats.CachesAvailableNum.Value++
- cacheGroupStats := stat.CacheGroups[enum.CacheGroupName(cacheGroup)]
+ cacheGroupStats := stat.CacheGroups[cacheGroup]
cacheGroupStats.IsAvailable.Value = true
- stat.CacheGroups[enum.CacheGroupName(cacheGroup)] = cacheGroupStats
+ stat.CacheGroups[cacheGroup] = cacheGroupStats
stat.TotalStats.IsAvailable.Value = true
typeStats := stat.Types[cacheType]
typeStats.IsAvailable.Value = true
@@ -91,13 +118,13 @@ func addAvailableData(dsStats Stats, crStates peer.Crstates, serverCachegroups m
}
// TODO fix nested ifs
- if results, ok := statHistory[enum.CacheName(cache)]; ok {
+ if results, ok := statHistory[cache]; ok {
if len(results) < 1 {
log.Warnf("no results %v %v\n", cache, deliveryService)
} else {
result := results[0]
if result.PrecomputedData.Reporting {
- stat.CommonStats.CachesReporting[enum.CacheName(cache)] = true
+ stat.CommonStats.CachesReporting[cache] = true
} else {
log.Debugf("no reporting %v %v\n", cache, deliveryService)
}
@@ -106,7 +133,7 @@ func addAvailableData(dsStats Stats, crStates peer.Crstates, serverCachegroups m
log.Debugf("no result for %v %v\n", cache, deliveryService)
}
- dsStats.DeliveryService[enum.DeliveryServiceName(deliveryService)] = stat // TODO Necessary? Remove?
+ dsStats.DeliveryService[deliveryService] = stat // TODO Necessary? Remove?
}
}
return dsStats, nil
@@ -118,10 +145,12 @@ type LastStats struct {
Caches map[enum.CacheName]LastStatsData
}
+// NewLastStats returns a new LastStats object, initializing internal pointer values.
func NewLastStats() LastStats {
return LastStats{DeliveryServices: map[enum.DeliveryServiceName]LastDSStat{}, Caches: map[enum.CacheName]LastStatsData{}}
}
+// Copy performs a deep copy of this LastStats object.
func (a LastStats) Copy() LastStats {
b := NewLastStats()
for k, v := range a.DeliveryServices {
@@ -133,6 +162,7 @@ func (a LastStats) Copy() LastStats {
return b
}
+// LastDSStat maps and aggregates the last stats received for the given delivery service to caches, cache groups, types, and total.
// TODO figure a way to associate this type with StatHTTP, with which its members correspond.
type LastDSStat struct {
Caches map[enum.CacheName]LastStatsData
@@ -141,6 +171,7 @@ type LastDSStat struct {
Total LastStatsData
}
+// Copy performs a deep copy of this LastDSStat object.
func (a LastDSStat) Copy() LastDSStat {
b := LastDSStat{
CacheGroups: map[enum.CacheGroupName]LastStatsData{},
@@ -168,6 +199,7 @@ func newLastDSStat() LastDSStat {
}
}
+// LastStatsData contains the last stats and per-second calculations for bytes and status codes received from a cache.
type LastStatsData struct {
Bytes LastStatData
Status2xx LastStatData
@@ -187,6 +219,7 @@ func (a LastStatsData) Sum(b LastStatsData) LastStatsData {
}
}
+// LastStatData contains the value, time it was received, and per-second calculation since the previous stat, for a stat from a cache.
type LastStatData struct {
PerSec float64
Stat int64
@@ -201,6 +234,7 @@ func (a LastStatData) Sum(b LastStatData) LastStatData {
}
}
+// BytesPerKilobit is the number of bytes in a kilobit.
const BytesPerKilobit = 125
func addLastStat(lastData LastStatData, newStat int64, newStatTime time.Time) (LastStatData, error) {
@@ -298,7 +332,7 @@ func addDSPerSecStats(dsName enum.DeliveryServiceName, stat dsdata.Stat, lastSta
for cacheName, cacheStats := range stat.Caches {
lastStat.Caches[cacheName], err = addLastStats(lastStat.Caches[cacheName], cacheStats, dsStatsTime)
if err != nil {
- log.Errorf("debugq %v Error adding kbps for cache %v: %v", cacheName, err)
+ log.Errorf("%v adding kbps for cache %v: %v", dsName, cacheName, err)
continue
}
cacheStats.Kbps.Value = lastStat.Caches[cacheName].Bytes.PerSec / BytesPerKilobit
@@ -371,15 +405,16 @@ func addPerSecStats(statHistory map[enum.CacheName][]cache.Result, dsStats Stats
return dsStats, lastStats
}
+// CreateStats aggregates and creates statistics from given stat history. It returns the created stats, information about these stats necessary for the next calculation, and any error.
func CreateStats(statHistory map[enum.CacheName][]cache.Result, toData todata.TOData, crStates peer.Crstates, lastStats LastStats, now time.Time) (Stats, LastStats, error) {
start := time.Now()
dsStats := NewStats()
- for deliveryService, _ := range toData.DeliveryServiceServers {
+ for deliveryService := range toData.DeliveryServiceServers {
if deliveryService == "" {
log.Errorf("EMPTY CreateStats deliveryService")
continue
}
- dsStats.DeliveryService[enum.DeliveryServiceName(deliveryService)] = *dsdata.NewStat()
+ dsStats.DeliveryService[deliveryService] = *dsdata.NewStat()
}
dsStats = setStaticData(dsStats, toData.DeliveryServiceServers)
var err error
@@ -397,7 +432,7 @@ func CreateStats(statHistory map[enum.CacheName][]cache.Result, toData todata.TO
log.Warnf("server %s has no cachegroup, skipping\n", server)
continue
}
- serverType, ok := toData.ServerTypes[enum.CacheName(server)]
+ serverType, ok := toData.ServerTypes[server]
if !ok {
log.Warnf("server %s not in CRConfig, skipping\n", server)
continue
@@ -428,13 +463,20 @@ func CreateStats(statHistory map[enum.CacheName][]cache.Result, toData todata.TO
perSecStats, lastStats := addPerSecStats(statHistory, dsStats, lastStats, now, toData.ServerCachegroups, toData.ServerTypes)
log.Infof("CreateStats took %v\n", time.Since(start))
+ perSecStats.Time = time.Now()
return perSecStats, lastStats, nil
}
func addStatCacheStats(s *dsdata.StatsOld, c dsdata.StatCacheStats, deliveryService enum.DeliveryServiceName, prefix string, t int64, filter dsdata.Filter) *dsdata.StatsOld {
add := func(name, val string) {
if filter.UseStat(name) {
- s.DeliveryService[deliveryService][dsdata.StatName(prefix+name)] = []dsdata.StatOld{dsdata.StatOld{Time: t, Value: val}}
+ // This is for compatibility with the Traffic Monitor 1.0 API.
+ // TODO abstract this? Or deprecate and remove it?
+ if name == "isAvailable" || name == "error-string" {
+ s.DeliveryService[deliveryService][dsdata.StatName("location."+prefix+name)] = []dsdata.StatOld{dsdata.StatOld{Time: t, Value: val}}
+ } else {
+ s.DeliveryService[deliveryService][dsdata.StatName(prefix+name)] = []dsdata.StatOld{dsdata.StatOld{Time: t, Value: val}}
+ }
}
}
add("out_bytes", strconv.Itoa(int(c.OutBytes.Value)))
@@ -449,7 +491,7 @@ func addStatCacheStats(s *dsdata.StatsOld, c dsdata.StatCacheStats, deliveryServ
add("tps_4xx", fmt.Sprintf("%f", c.Tps4xx.Value))
add("tps_3xx", fmt.Sprintf("%f", c.Tps3xx.Value))
add("tps_2xx", fmt.Sprintf("%f", c.Tps2xx.Value))
- add("error", c.ErrorString.Value)
+ add("error-string", c.ErrorString.Value)
add("tps_total", strconv.Itoa(int(c.TpsTotal.Value)))
return s
}
@@ -470,16 +512,16 @@ func addCommonData(s *dsdata.StatsOld, c *dsdata.StatCommon, deliveryService enu
return s
}
-// StatsJSON returns an object formatted as expected to be serialized to JSON and served.
-func (dsStats Stats) JSON(filter dsdata.Filter, params url.Values) dsdata.StatsOld {
- now := time.Now().Unix()
+// JSON returns an object formatted as expected to be serialized to JSON and served.
+func (s Stats) JSON(filter dsdata.Filter, params url.Values) dsdata.StatsOld {
+ // TODO fix to be the time calculated, not the time requested
+ now := s.Time.UnixNano() / int64(time.Millisecond) // Traffic Monitor 1.0 API is 'ms since the epoch'
jsonObj := &dsdata.StatsOld{
+ CommonAPIData: srvhttp.GetCommonAPIData(params, time.Now()),
DeliveryService: map[enum.DeliveryServiceName]map[dsdata.StatName][]dsdata.StatOld{},
- QueryParams: http_server.ParametersStr(params),
- DateStr: http_server.DateStr(time.Now()),
}
- for deliveryService, stat := range dsStats.DeliveryService {
+ for deliveryService, stat := range s.DeliveryService {
if !filter.UseDeliveryService(deliveryService) {
continue
}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/deliveryservicedata/stat.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/deliveryservicedata/stat.go b/traffic_monitor/experimental/traffic_monitor/deliveryservicedata/stat.go
index 16680e4..cce4a8e 100644
--- a/traffic_monitor/experimental/traffic_monitor/deliveryservicedata/stat.go
+++ b/traffic_monitor/experimental/traffic_monitor/deliveryservicedata/stat.go
@@ -1,8 +1,29 @@
package deliveryservicedata // TODO rename?
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"errors"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/srvhttp"
"net/url"
"time"
)
@@ -15,25 +36,30 @@ type Filter interface {
WithinStatHistoryMax(int) bool
}
+// StatName is the name of a stat.
type StatName string
+
+// StatOld is the old JSON representation of a stat, from Traffic Monitor 1.0.
type StatOld struct {
Time int64 `json:"time"`
Value string `json:"value"`
Span int `json:"span,omitempty"` // TODO set? remove?
Index int `json:"index,omitempty"` // TODO set? remove?
}
+
+// StatsOld is the old JSON representation of stats, from Traffic Monitor 1.0. It is designed to be serialized and returns from an API, and includes stat history for each delivery service, as well as data common to most endpoints.
type StatsOld struct {
- // TODO move QueryParams, DateStr to a 'EndpointCommon' struct
DeliveryService map[enum.DeliveryServiceName]map[StatName][]StatOld `json:"deliveryService"`
- QueryParams string `json:"pp"`
- DateStr string `json:"date"`
+ srvhttp.CommonAPIData
}
+// StatsReadonly is a read-only interface for delivery service Stats, designed to be passed to multiple goroutine readers.
type StatsReadonly interface {
Get(enum.DeliveryServiceName) (StatReadonly, bool)
JSON(Filter, url.Values) StatsOld
}
+// StatReadonly is a read-only interface for a delivery service Stat, designed to be passed to multiple goroutine readers.
type StatReadonly interface {
Copy() Stat
Common() StatCommonReadonly
@@ -42,6 +68,7 @@ type StatReadonly interface {
Total() StatCacheStats
}
+// StatCommonReadonly is a read-only interface for a delivery service's common Stat data, designed to be passed to multiple goroutine readers.
type StatCommonReadonly interface {
Copy() StatCommon
CachesConfigured() StatInt
@@ -53,27 +80,36 @@ type StatCommonReadonly interface {
CachesAvailable() StatInt
}
-// New, more structured format:
+// StatMeta includes metadata about a particular stat.
type StatMeta struct {
- Time int `json:"time"`
+ Time int64 `json:"time"`
}
+
+// StatFloat is a float stat, combined with its metadata
type StatFloat struct {
StatMeta
Value float64 `json:"value"`
}
+
+// StatBool is a boolean stat, combined with its metadata
type StatBool struct {
StatMeta
Value bool `json:"value"`
}
+
+// StatInt is an integer stat, combined with its metadata
type StatInt struct {
StatMeta
Value int64 `json:"value"`
}
+
+// StatString is a string stat, combined with its metadata
type StatString struct {
StatMeta
Value string `json:"value"`
}
+// StatCommon contains stat data common to most delivery service stats.
type StatCommon struct {
CachesConfiguredNum StatInt `json:"caches_configured"`
CachesReporting map[enum.CacheName]bool `json:"caches_reporting"`
@@ -84,6 +120,7 @@ type StatCommon struct {
CachesAvailableNum StatInt `json:"caches_available"`
}
+// Copy returns a deep copy of this StatCommon object.
func (a StatCommon) Copy() StatCommon {
b := a
for k, v := range a.CachesReporting {
@@ -92,32 +129,47 @@ func (a StatCommon) Copy() StatCommon {
return b
}
+// CachesConfigured returns the number of caches configured for this delivery service stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) CachesConfigured() StatInt {
return a.CachesConfiguredNum
}
+
+// CacheReporting returns the number of caches reporting for this delivery service stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) CacheReporting(name enum.CacheName) (bool, bool) {
c, ok := a.CachesReporting[name]
return c, ok
}
+
+// CachesReportingNames returns the list of caches reporting for this delivery service stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) CachesReportingNames() []enum.CacheName {
names := make([]enum.CacheName, 0, len(a.CachesReporting))
- for name, _ := range a.CachesReporting {
+ for name := range a.CachesReporting {
names = append(names, name)
}
return names
}
+
+// Error returns the error string of this delivery service stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) Error() StatString {
return a.ErrorStr
}
+
+// Status returns the status string of this delivery service stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) Status() StatString {
return a.StatusStr
}
+
+// Healthy returns whether this delivery service is considered healthy by this stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) Healthy() StatBool {
return a.IsHealthy
}
+
+// Available returns whether this delivery service is considered available by this stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) Available() StatBool {
return a.IsAvailable
}
+
+// CachesAvailable returns the number of caches available to the delivery service in this stat. It is part of the StatCommonReadonly interface.
func (a StatCommon) CachesAvailable() StatInt {
return a.CachesAvailableNum
}
@@ -142,6 +194,7 @@ type StatCacheStats struct {
TpsTotal StatInt `json:"tps_total"`
}
+// Sum adds the given cache stats to this cache stats. Numeric values are summed; strings are appended.
func (a StatCacheStats) Sum(b StatCacheStats) StatCacheStats {
return StatCacheStats{
OutBytes: StatInt{Value: a.OutBytes.Value + b.OutBytes.Value},
@@ -161,6 +214,7 @@ func (a StatCacheStats) Sum(b StatCacheStats) StatCacheStats {
}
}
+// Stat represents a complete delivery service stat, for a given poll, or at the time requested.
type Stat struct {
CommonStats StatCommon
CacheGroups map[enum.CacheGroupName]StatCacheStats
@@ -170,8 +224,10 @@ type Stat struct {
TotalStats StatCacheStats
}
+// ErrNotProcessedStat indicates a stat received is not used by Traffic Monitor, nor returned by any API endpoint. Receiving this error indicates the stat has been discarded.
var ErrNotProcessedStat = errors.New("This stat is not used.")
+// NewStat returns a new delivery service Stat, initializing pointer members.
func NewStat() *Stat {
return &Stat{
CacheGroups: map[enum.CacheGroupName]StatCacheStats{},
@@ -182,6 +238,7 @@ func NewStat() *Stat {
}
}
+// Copy performs a deep copy of this Stat. It does not modify, and is thus safe for multiple goroutines.
func (a Stat) Copy() Stat {
b := Stat{
CommonStats: a.CommonStats.Copy(),
@@ -206,20 +263,24 @@ func (a Stat) Copy() Stat {
return b
}
+// Common returns the common stat data for this stat. It is part of the StatCommonReadonly interface.
func (a Stat) Common() StatCommonReadonly {
return a.CommonStats
}
+// CacheGroup returns the data for the given cachegroup in this stat. It is part of the StatCommonReadonly interface.
func (a Stat) CacheGroup(name enum.CacheGroupName) (StatCacheStats, bool) {
c, ok := a.CacheGroups[name]
return c, ok
}
+// Type returns the aggregated data for the given cache type in this stat. It is part of the StatCommonReadonly interface.
func (a Stat) Type(name enum.CacheType) (StatCacheStats, bool) {
t, ok := a.Types[name]
return t, ok
}
+// Total returns the aggregated total data in this stat. It is part of the StatCommonReadonly interface.
func (a Stat) Total() StatCacheStats {
return a.TotalStats
}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/enum/enum.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/enum/enum.go b/traffic_monitor/experimental/traffic_monitor/enum/enum.go
index d14593c..77f8ea4 100644
--- a/traffic_monitor/experimental/traffic_monitor/enum/enum.go
+++ b/traffic_monitor/experimental/traffic_monitor/enum/enum.go
@@ -1,29 +1,56 @@
-// enum contains enumerations and strongly typed names.
+// Package enum contains enumerations and strongly typed names.
// The names are an experiment with strong typing of string types. The primary goal is to make code more self-documenting, especially map keys. If peole don't like it, we can get rid of it.
package enum
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"strings"
)
+// TrafficMonitorName is the hostname of a Traffic Monitor peer.
type TrafficMonitorName string
+// CacheName is the hostname of a CDN cache.
type CacheName string
+// CacheGroupName is the name of a CDN cachegroup.
type CacheGroupName string
-// Current JSON endpoint:
+// DeliveryServiceName is the name of a CDN delivery service.
type DeliveryServiceName string
-// TODO move and rename more generically
+// CacheType is the type (or tier) of a CDN cache.
type CacheType string
const (
- CacheTypeEdge = CacheType("EDGE")
- CacheTypeMid = CacheType("MID")
+ // CacheTypeEdge represents an edge cache.
+ CacheTypeEdge = CacheType("EDGE")
+ // CacheTypeMid represents a mid cache.
+ CacheTypeMid = CacheType("MID")
+ // CacheTypeInvalid represents an cache type enumeration. Note this is the default construction for a CacheType.
CacheTypeInvalid = CacheType("")
)
+// String returns a string representation of this cache type.
func (t CacheType) String() string {
switch t {
case CacheTypeEdge:
@@ -31,10 +58,11 @@ func (t CacheType) String() string {
case CacheTypeMid:
return "MID"
default:
- return "INVALID"
+ return "INVALIDCACHETYPE"
}
}
+// CacheTypeFromString returns a cache type object from its string representation, or CacheTypeInvalid if the string is not a valid type.
func CacheTypeFromString(s string) CacheType {
s = strings.ToLower(s)
switch s {
@@ -51,11 +79,15 @@ func CacheTypeFromString(s string) CacheType {
type DSType string
const (
- DSTypeHTTP = DSType("http")
- DSTypeDNS = DSType("dns")
+ // DSTypeHTTP represents an HTTP delivery service
+ DSTypeHTTP = DSType("http")
+ // DSTypeDNS represents a DNS delivery service
+ DSTypeDNS = DSType("dns")
+ // DSTypeInvalid represents an invalid delivery service type enumeration. Note this is the default construction for a DSType.
DSTypeInvalid = DSType("")
)
+// String returns a string representation of this delivery service type.
func (t DSType) String() string {
switch t {
case DSTypeHTTP:
@@ -63,10 +95,11 @@ func (t DSType) String() string {
case DSTypeDNS:
return "DNS"
default:
- return "INVALID"
+ return "INVALIDDSTYPE"
}
}
+// DSTypeFromString returns a delivery service type object from its string representation, or DSTypeInvalid if the string is not a valid type.
func DSTypeFromString(s string) DSType {
s = strings.ToLower(s)
switch s {
@@ -78,3 +111,54 @@ func DSTypeFromString(s string) DSType {
return DSTypeInvalid
}
}
+
+// CacheStatus represents the Traffic Server status set in Traffic Ops (online, offline, admin_down, reported). The string values of this type should match the Traffic Ops values.
+type CacheStatus string
+
+const (
+ // CacheStatusAdminDown represents a cache which has been administratively marked as down, but which should still appear in the CDN (Traffic Server, Traffic Monitor, Traffic Router).
+ CacheStatusAdminDown = CacheStatus("ADMIN_DOWN")
+ // CacheStatusOnline represents a cache which has been marked as Online in Traffic Ops, irrespective of monitoring. Traffic Monitor will always flag these caches as available.
+ CacheStatusOnline = CacheStatus("ONLINE")
+ // CacheStatusOffline represents a cache which has been marked as Offline in Traffic Ops. These caches will not be returned in any endpoint, and Traffic Monitor acts like they don't exist.
+ CacheStatusOffline = CacheStatus("OFFLINE")
+ // CacheStatusReported represents a cache which has been marked as Reported in Traffic Ops. These caches are polled for health and returned in endpoints as available or unavailable based on bandwidth, response time, and other factors. The vast majority of caches should be Reported.
+ CacheStatusReported = CacheStatus("REPORTED")
+ // CacheStatusInvalid represents an invalid status enumeration.
+ CacheStatusInvalid = CacheStatus("")
+)
+
+// String returns a string representation of this cache status
+func (t CacheStatus) String() string {
+ switch t {
+ case CacheStatusAdminDown:
+ fallthrough
+ case CacheStatusOnline:
+ fallthrough
+ case CacheStatusOffline:
+ fallthrough
+ case CacheStatusReported:
+ return string(t)
+ default:
+ return "INVALIDCACHESTATUS"
+ }
+}
+
+// CacheStatusFromString returns a CacheStatus from its string representation, or CacheStatusInvalid if the string is not a valid type.
+func CacheStatusFromString(s string) CacheStatus {
+ s = strings.ToLower(s)
+ switch s {
+ case "admin_down":
+ fallthrough
+ case "admindown":
+ return CacheStatusAdminDown
+ case "offline":
+ return CacheStatusOffline
+ case "online":
+ return CacheStatusOnline
+ case "reported":
+ return CacheStatusReported
+ default:
+ return CacheStatusInvalid
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/health/cache_health.go b/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
index b8b180f..5dfa0c2 100644
--- a/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
+++ b/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
@@ -1,43 +1,44 @@
package health
-import (
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/common/log"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/cache"
- traffic_ops "github.com/Comcast/traffic_control/traffic_ops/client"
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
"fmt"
+ "math"
"strconv"
"strings"
-)
-
-// Get the String value of one of those pesky map[string]interface{} things that seem so easy
-func getString(key string, intface map[string]interface{}) (string, error) {
- str, ok := intface[key].(string)
-
- if ok {
- return str, nil
- } else {
- return "", fmt.Errorf("Error in getString: No string found for key %s", key)
- }
-}
+ "time"
-// Get the float64 value of one of those pesky map[string]interface{} things that seem so easy
-func getNumber(key string, intface map[string]interface{}) (float64, error) {
- val, ok := intface[key].(float64)
-
- if ok {
- return val, nil
- } else {
- return -1, fmt.Errorf("Error in getNumber: No number found for %s", key)
- }
-}
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
+ traffic_ops "github.com/apache/incubator-trafficcontrol/traffic_ops/client"
+)
func setError(newResult *cache.Result, err error) {
newResult.Error = err
newResult.Available = false
}
-// Get the vitals to decide health on in the right format
+// GetVitals Gets the vitals to decide health on in the right format
func GetVitals(newResult *cache.Result, prevResult *cache.Result, mc *traffic_ops.TrafficMonitorConfigMap) {
if newResult.Error != nil {
log.Errorf("cache_health.GetVitals() called with an errored Result!")
@@ -54,7 +55,7 @@ func GetVitals(newResult *cache.Result, prevResult *cache.Result, mc *traffic_op
}
newResult.Vitals.LoadAvg = oneMinAvg
} else {
- setError(newResult, fmt.Errorf("Can't make sense of '%s' as a load average for %s", newResult.Astats.System.ProcLoadavg, newResult.Id))
+ setError(newResult, fmt.Errorf("Can't make sense of '%s' as a load average for %s", newResult.Astats.System.ProcLoadavg, newResult.ID))
return
}
@@ -90,27 +91,63 @@ func GetVitals(newResult *cache.Result, prevResult *cache.Result, mc *traffic_op
// inf.speed -- value looks like "10000" (without the quotes) so it is in Mbps.
// TODO JvD: Should we really be running this code every second for every cache polled????? I don't think so.
interfaceBandwidth := newResult.Astats.System.InfSpeed
- newResult.Vitals.MaxKbpsOut = int64(interfaceBandwidth)*1000 - mc.Profile[mc.TrafficServer[string(newResult.Id)].Profile].Parameters.MinFreeKbps
+ newResult.Vitals.MaxKbpsOut = int64(interfaceBandwidth)*1000 - mc.Profile[mc.TrafficServer[string(newResult.ID)].Profile].Parameters.MinFreeKbps
// log.Infoln(newResult.Id, "BytesOut", newResult.Vitals.BytesOut, "BytesIn", newResult.Vitals.BytesIn, "Kbps", newResult.Vitals.KbpsOut, "max", newResult.Vitals.MaxKbpsOut)
}
+// getKbpsThreshold returns the numeric kbps threshold, from the Traffic Ops string value. If there is a parse error, it logs a warning and returns the max floating point number, signifying no limit
+// TODO add float64 to Traffic Ops Client interface
+func getKbpsThreshold(threshStr string) int64 {
+ if len(threshStr) == 0 {
+ log.Errorf("Empty Traffic Ops HealthThresholdAvailableBandwidthInKbps; setting no limit.\n")
+ return math.MaxInt64
+ }
+ if threshStr[0] == '>' {
+ threshStr = threshStr[1:]
+ }
+ thresh, err := strconv.ParseInt(threshStr, 10, 64)
+ if err != nil {
+ log.Errorf("Failed to parse Traffic Ops HealthThresholdAvailableBandwidthInKbps, setting no limit: '%v'\n", err)
+ return math.MaxInt64
+ }
+ return thresh
+}
+
+// TODO add time.Duration to Traffic Ops Client interface
+func getQueryThreshold(threshInt int64) time.Duration {
+ return time.Duration(threshInt) * time.Millisecond
+}
+
+func cacheCapacityKbps(result cache.Result) int64 {
+ kbpsInMbps := int64(1000)
+ return int64(result.Astats.System.InfSpeed) * kbpsInMbps
+}
+
// EvalCache returns whether the given cache should be marked available, and a string describing why
func EvalCache(result cache.Result, mc *traffic_ops.TrafficMonitorConfigMap) (bool, string) {
- status := mc.TrafficServer[string(result.Id)].Status
+ toServer := mc.TrafficServer[string(result.ID)]
+ status := enum.CacheStatusFromString(toServer.Status)
+ if status == enum.CacheStatusInvalid {
+ log.Errorf("Cache %v got invalid status from Traffic Ops '%v' - treating as Reported\n", result.ID, toServer.Status)
+ }
+ params := mc.Profile[toServer.Profile].Parameters
switch {
- case status == "ADMIN_DOWN":
- return false, "set to ADMIN_DOWN"
- case status == "OFFLINE":
- return false, "set to OFFLINE"
- case status == "ONLINE":
- return true, "set to ONLINE"
+ case status == enum.CacheStatusAdminDown:
+ return false, "set to " + status.String()
+ case status == enum.CacheStatusOffline:
+ log.Errorf("Cache %v set to offline, but still polled\n", result.ID)
+ return false, "set to " + status.String()
+ case status == enum.CacheStatusOnline:
+ return true, "set to " + status.String()
case result.Error != nil:
return false, fmt.Sprintf("error: %v", result.Error)
- case result.Vitals.LoadAvg > mc.Profile[mc.TrafficServer[string(result.Id)].Profile].Parameters.HealthThresholdLoadAvg:
- return false, fmt.Sprintf("load average %f exceeds threshold %f", result.Vitals.LoadAvg, mc.Profile[mc.TrafficServer[string(result.Id)].Profile].Parameters.HealthThresholdLoadAvg)
- case result.Vitals.MaxKbpsOut < result.Vitals.KbpsOut:
- return false, fmt.Sprintf("%dkbps exceeds max %dkbps", result.Vitals.KbpsOut, result.Vitals.MaxKbpsOut)
+ case result.Vitals.LoadAvg > params.HealthThresholdLoadAvg:
+ return false, fmt.Sprintf("load average %f exceeds threshold %f", result.Vitals.LoadAvg, params.HealthThresholdLoadAvg)
+ case result.Vitals.KbpsOut > cacheCapacityKbps(result)-getKbpsThreshold(params.HealthThresholdAvailableBandwidthInKbps):
+ return false, fmt.Sprintf("%dkbps exceeds max %dkbps", result.Vitals.KbpsOut, getKbpsThreshold(params.HealthThresholdAvailableBandwidthInKbps))
+ case result.RequestTime > getQueryThreshold(int64(params.HealthThresholdQueryTime)):
+ return false, fmt.Sprintf("request time %v exceeds max %v", result.RequestTime, getQueryThreshold(int64(params.HealthThresholdQueryTime)))
default:
return result.Available, "reported"
}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/http_server/http_server.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/http_server/http_server.go b/traffic_monitor/experimental/traffic_monitor/http_server/http_server.go
deleted file mode 100644
index fb70d72..0000000
--- a/traffic_monitor/experimental/traffic_monitor/http_server/http_server.go
+++ /dev/null
@@ -1,289 +0,0 @@
-package http_server
-
-import (
- "fmt"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/common/log"
- "github.com/hydrogen18/stoppableListener"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "sync"
- "time"
-)
-
-// Server is a re-runnable HTTP server. Server.Run() may be called repeatedly, and
-// each time the previous running server will be stopped, and the server will be
-// restarted with the new port address and data request channel.
-type Server struct {
- getData GetDataFunc
- stoppableListener *stoppableListener.StoppableListener
- stoppableListenerWaitGroup sync.WaitGroup
-}
-
-// Endpoints returns a map of HTTP paths to functions.
-// This is a function because Go doesn't have constant map literals.
-func (s Server) endpoints() (map[string]http.HandlerFunc, error) {
- handleRoot, err := s.handleRootFunc()
- handleSortableJs, err := s.handleSortableFunc()
- if err != nil {
- return nil, fmt.Errorf("Error getting root endpoint: %v", err)
- }
-
- // note: with the trailing slash, any non-trailing slash requests will get a 301 redirect
- return map[string]http.HandlerFunc{
- "/publish/CacheStats/": s.dataRequestFunc(CacheStats),
- "/publish/CacheStats": s.dataRequestFunc(CacheStats),
- "/publish/CrConfig/": s.dataRequestFunc(TRConfig),
- "/publish/CrConfig": s.dataRequestFunc(TRConfig),
- "/publish/CrStates/": s.handleCrStatesFunc(),
- "/publish/CrStates": s.handleCrStatesFunc(),
- "/publish/DsStats/": s.dataRequestFunc(DSStats),
- "/publish/DsStats": s.dataRequestFunc(DSStats),
- "/publish/EventLog/": s.dataRequestFunc(EventLog),
- "/publish/EventLog": s.dataRequestFunc(EventLog),
- "/publish/PeerStates/": s.dataRequestFunc(PeerStates),
- "/publish/PeerStates": s.dataRequestFunc(PeerStates),
- "/publish/StatSummary/": s.dataRequestFunc(StatSummary),
- "/publish/StatSummary": s.dataRequestFunc(StatSummary),
- "/publish/Stats/": s.dataRequestFunc(Stats),
- "/publish/Stats": s.dataRequestFunc(Stats),
- "/publish/ConfigDoc/": s.dataRequestFunc(ConfigDoc),
- "/publish/ConfigDoc": s.dataRequestFunc(ConfigDoc),
- "/api/cache-count/": s.dataRequestFunc(APICacheCount),
- "/api/cache-count": s.dataRequestFunc(APICacheCount),
- "/api/cache-available-count/": s.dataRequestFunc(APICacheAvailableCount),
- "/api/cache-available-count": s.dataRequestFunc(APICacheAvailableCount),
- "/api/cache-down-count/": s.dataRequestFunc(APICacheDownCount),
- "/api/cache-down-count": s.dataRequestFunc(APICacheDownCount),
- "/api/version/": s.dataRequestFunc(APIVersion),
- "/api/version": s.dataRequestFunc(APIVersion),
- "/api/traffic-ops-uri/": s.dataRequestFunc(APITrafficOpsURI),
- "/api/traffic-ops-uri": s.dataRequestFunc(APITrafficOpsURI),
- "/api/cache-statuses/": s.dataRequestFunc(APICacheStates),
- "/api/cache-statuses": s.dataRequestFunc(APICacheStates),
- "/api/bandwidth-kbps/": s.dataRequestFunc(APIBandwidthKbps),
- "/api/bandwidth-kbps": s.dataRequestFunc(APIBandwidthKbps),
- "/api/bandwidth-capacity-kbps/": s.dataRequestFunc(APIBandwidthCapacityKbps),
- "/api/bandwidth-capacity-kbps": s.dataRequestFunc(APIBandwidthCapacityKbps),
- "/": handleRoot,
- "/sorttable.js": handleSortableJs,
- }, nil
-}
-
-func (s Server) registerEndpoints(sm *http.ServeMux) error {
- endpoints, err := s.endpoints()
- if err != nil {
- return err
- }
- for path, f := range endpoints {
- sm.HandleFunc(path, f)
- }
- return nil
-}
-
-// Run runs a new HTTP service at the given addr, making data requests to the given c.
-// Run may be called repeatedly, and each time, will shut down any existing service first.
-// Run is NOT threadsafe, and MUST NOT be called concurrently by multiple goroutines.
-func (s Server) Run(f GetDataFunc, addr string) error {
- // TODO make an object, which itself is not threadsafe, but which encapsulates all data so multiple
- // objects can be created and Run.
-
- if s.stoppableListener != nil {
- log.Infof("Stopping Web Server\n")
- s.stoppableListener.Stop()
- s.stoppableListenerWaitGroup.Wait()
- }
- log.Infof("Starting Web Server\n")
-
- var err error
- var originalListener net.Listener
- if originalListener, err = net.Listen("tcp", addr); err != nil {
- return err
- }
- if s.stoppableListener, err = stoppableListener.New(originalListener); err != nil {
- return err
- }
-
- s.getData = f
-
- sm := http.NewServeMux()
- err = s.registerEndpoints(sm)
- if err != nil {
- return err
- }
- server := &http.Server{
- Addr: addr,
- Handler: sm,
- ReadTimeout: 10 * time.Second,
- WriteTimeout: 10 * time.Second,
- MaxHeaderBytes: 1 << 20,
- }
-
- s.stoppableListenerWaitGroup = sync.WaitGroup{}
- s.stoppableListenerWaitGroup.Add(1)
- go func() {
- defer s.stoppableListenerWaitGroup.Done()
- server.Serve(s.stoppableListener)
- }()
-
- log.Infof("Web server listening on %s", addr)
- return nil
-}
-
-type Type int
-
-const (
- TRConfig Type = (1 << iota)
- TRStateDerived
- TRStateSelf
- CacheStats
- DSStats
- EventLog
- PeerStates
- StatSummary
- Stats
- ConfigDoc
- APICacheCount
- APICacheAvailableCount
- APICacheDownCount
- APIVersion
- APITrafficOpsURI
- APICacheStates
- APIBandwidthKbps
- APIBandwidthCapacityKbps
-)
-
-func (t Type) String() string {
- switch t {
- case TRConfig:
- return "TRConfig"
- case TRStateDerived:
- return "TRStateDerived"
- case TRStateSelf:
- return "TRStateSelf"
- case CacheStats:
- return "CacheStats"
- case DSStats:
- return "DSStats"
- case EventLog:
- return "EventLog"
- case PeerStates:
- return "PeerStates"
- case StatSummary:
- return "StatSummary"
- case Stats:
- return "Stats"
- case ConfigDoc:
- return "ConfigDoc"
- case APICacheCount:
- return "APICacheCount"
- case APICacheAvailableCount:
- return "APICacheAvailableCount"
- case APICacheDownCount:
- return "APICacheDownCount"
- case APIVersion:
- return "APIVersion"
- case APITrafficOpsURI:
- return "APITrafficOpsURI"
- case APICacheStates:
- return "APICacheStates"
- case APIBandwidthKbps:
- return "APIBandwidthKbps"
- case APIBandwidthCapacityKbps:
- return "APIBandwidthCapacityKbps"
- default:
- return "Invalid"
- }
-}
-
-type Format int
-
-const (
- XML Format = (1 << iota)
- JSON
-)
-
-type DataRequest struct {
- Type
- Format
- Date string
- Parameters map[string][]string
-}
-
-type GetDataFunc func(DataRequest) ([]byte, int)
-
-// ParametersStr takes the URL query parameters, and returns a string as used by the Traffic Monitor 1.0 endpoints "pp" key.
-func ParametersStr(params url.Values) string {
- fmt.Println("debug4 ParametersStr 0")
- pp := ""
- for param, vals := range params {
- for _, val := range vals {
- pp += param + "=[" + val + "], "
- }
- }
- if len(pp) > 2 {
- pp = pp[:len(pp)-2]
- }
- return pp
-}
-
-// DateStr returns the given time in the format expected by Traffic Monitor 1.0 API users
-func DateStr(t time.Time) string {
- return t.UTC().Format("Mon Jan 02 15:04:05 UTC 2006")
-}
-
-func (s Server) dataRequest(w http.ResponseWriter, req *http.Request, t Type, f Format) {
- //pp: "0=[my-ats-edge-cache-0], hc=[1]",
- //dateLayout := "Thu Oct 09 20:28:36 UTC 2014"
- dateLayout := "Mon Jan 02 15:04:05 MST 2006"
- data, responseCode := s.getData(DataRequest{
- Type: t,
- Format: f,
- Date: time.Now().UTC().Format(dateLayout),
- Parameters: req.URL.Query(),
- })
- if len(data) > 0 {
- w.WriteHeader(responseCode)
- w.Write(data)
- } else {
- w.WriteHeader(http.StatusInternalServerError)
- w.Write([]byte("Internal Server Error"))
- }
-}
-
-func (s Server) handleRootFunc() (http.HandlerFunc, error) {
- index, err := ioutil.ReadFile("index.html")
- if err != nil {
- return nil, err
- }
- return func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "%s", index)
- }, nil
-}
-
-func (s Server) handleSortableFunc() (http.HandlerFunc, error) {
- index, err := ioutil.ReadFile("sorttable.js")
- if err != nil {
- return nil, err
- }
- return func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "%s", index)
- }, nil
-}
-
-func (s Server) handleCrStatesFunc() http.HandlerFunc {
- return func(w http.ResponseWriter, req *http.Request) {
- t := TRStateDerived
- if req.URL.RawQuery == "raw" {
- t = TRStateSelf
- }
- s.dataRequest(w, req, t, JSON)
- }
-}
-
-func (s Server) dataRequestFunc(t Type) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
- s.dataRequest(w, r, t, JSON)
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/index.html
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/index.html b/traffic_monitor/experimental/traffic_monitor/index.html
index a5c43aa..43d1ab4 100644
--- a/traffic_monitor/experimental/traffic_monitor/index.html
+++ b/traffic_monitor/experimental/traffic_monitor/index.html
@@ -1,3 +1,22 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
<!DOCTYPE html>
<html>
<head>
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/manager/cacheavailablestatus.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/cacheavailablestatus.go b/traffic_monitor/experimental/traffic_monitor/manager/cacheavailablestatus.go
index b66c392..67860b1 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/cacheavailablestatus.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/cacheavailablestatus.go
@@ -1,25 +1,50 @@
package manager
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
"sync"
)
+// CacheAvailableStatusReported is the status string returned by caches set to "reported" in Traffic Ops.
// TODO put somewhere more generic
const CacheAvailableStatusReported = "REPORTED"
+// CacheAvailableStatus is the available status of the given cache. It includes a boolean available/unavailable flag, and a descriptive string.
type CacheAvailableStatus struct {
Available bool
Status string
}
+// CacheAvailableStatuses is the available status of each cache.
type CacheAvailableStatuses map[enum.CacheName]CacheAvailableStatus
+// CacheAvailableStatusThreadsafe wraps a map of cache available statuses to be safe for multiple reader goroutines and one writer.
type CacheAvailableStatusThreadsafe struct {
caches *CacheAvailableStatuses
m *sync.RWMutex
}
+// Copy copies this CacheAvailableStatuses. It does not modify, and thus is safe for multiple reader goroutines.
func (a CacheAvailableStatuses) Copy() CacheAvailableStatuses {
b := CacheAvailableStatuses(map[enum.CacheName]CacheAvailableStatus{})
for k, v := range a {
@@ -28,17 +53,20 @@ func (a CacheAvailableStatuses) Copy() CacheAvailableStatuses {
return b
}
+// NewCacheAvailableStatusThreadsafe creates and returns a new CacheAvailableStatusThreadsafe, initializing internal pointer values.
func NewCacheAvailableStatusThreadsafe() CacheAvailableStatusThreadsafe {
c := CacheAvailableStatuses(map[enum.CacheName]CacheAvailableStatus{})
return CacheAvailableStatusThreadsafe{m: &sync.RWMutex{}, caches: &c}
}
+// Get returns the internal map of cache statuses. The returned map MUST NOT be modified. If modification is necessary, copy.
func (o *CacheAvailableStatusThreadsafe) Get() CacheAvailableStatuses {
o.m.RLock()
defer o.m.RUnlock()
return *o.caches
}
+// Set sets the internal map of cache availability. This MUST NOT be called by multiple goroutines.
func (o *CacheAvailableStatusThreadsafe) Set(v CacheAvailableStatuses) {
o.m.Lock()
*o.caches = v
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go b/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
index 4651aa3..7de4c0e 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
@@ -1,5 +1,25 @@
package manager
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"encoding/json"
"fmt"
@@ -11,31 +31,35 @@ import (
"strings"
"time"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/common/log"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/cache"
- ds "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/deliveryservice"
- dsdata "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/enum"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/http_server"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/peer"
- todata "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
- towrap "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/trafficopswrapper"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
+ ds "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservice"
+ dsdata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/srvhttp"
+ todata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
+ towrap "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopswrapper"
+ to "github.com/apache/incubator-trafficcontrol/traffic_ops/client"
)
+// JSONEvents represents the structure we wish to serialize to JSON, for Events.
type JSONEvents struct {
Events []Event `json:"events"`
}
+// CacheState represents the available state of a cache.
type CacheState struct {
Value bool `json:"value"`
}
-type ApiPeerStates struct {
- Peers map[enum.TrafficMonitorName]map[enum.CacheName][]CacheState `json:"peers"`
- QueryParams string `json:"pp"`
- DateStr string `json:"date"`
+// APIPeerStates contains the data to be returned for an API call to get the peer states of a Traffic Monitor. This contains common API data returned by most endpoints, and a map of peers, to caches' states.
+type APIPeerStates struct {
+ srvhttp.CommonAPIData
+ Peers map[enum.TrafficMonitorName]map[enum.CacheName][]CacheState `json:"peers"`
}
+// CacheStatus contains summary stat data about the given cache.
// TODO make fields nullable, so error fields can be omitted, letting API callers still get updates for unerrored fields
type CacheStatus struct {
Type *string `json:"type,omitempty"`
@@ -56,6 +80,7 @@ type CacheStatFilter struct {
cacheTypes map[enum.CacheName]enum.CacheType
}
+// UseCache returns whether the given cache is in the filter.
func (f *CacheStatFilter) UseCache(name enum.CacheName) bool {
if _, inHosts := f.hosts[name]; len(f.hosts) != 0 && !inHosts {
return false
@@ -66,6 +91,7 @@ func (f *CacheStatFilter) UseCache(name enum.CacheName) bool {
return true
}
+// UseStat returns whether the given stat is in the filter.
func (f *CacheStatFilter) UseStat(statName string) bool {
if len(f.statsToUse) == 0 {
return true
@@ -74,7 +100,7 @@ func (f *CacheStatFilter) UseStat(statName string) bool {
_, ok := f.statsToUse[statName]
return ok
}
- for statToUse, _ := range f.statsToUse {
+ for statToUse := range f.statsToUse {
if strings.Contains(statName, statToUse) {
return true
}
@@ -82,6 +108,7 @@ func (f *CacheStatFilter) UseStat(statName string) bool {
return false
}
+// WithinStatHistoryMax returns whether the given history index is less than the max history of this filter.
func (f *CacheStatFilter) WithinStatHistoryMax(n int) bool {
if f.historyCount == 0 {
return true
@@ -103,7 +130,7 @@ func NewCacheStatFilter(params url.Values, cacheTypes map[enum.CacheName]enum.Ca
if len(params) > len(validParams) {
return nil, fmt.Errorf("invalid query parameters")
}
- for param, _ := range params {
+ for param := range params {
if _, ok := validParams[param]; !ok {
return nil, fmt.Errorf("invalid query parameter '%v'", param)
}
@@ -172,6 +199,7 @@ type DSStatFilter struct {
dsTypes map[enum.DeliveryServiceName]enum.DSType
}
+// UseDeliveryService returns whether the given delivery service is in this filter.
func (f *DSStatFilter) UseDeliveryService(name enum.DeliveryServiceName) bool {
if _, inDSes := f.deliveryServices[name]; len(f.deliveryServices) != 0 && !inDSes {
return false
@@ -182,6 +210,7 @@ func (f *DSStatFilter) UseDeliveryService(name enum.DeliveryServiceName) bool {
return true
}
+// UseStat returns whether the given stat is in this filter.
func (f *DSStatFilter) UseStat(statName string) bool {
if len(f.statsToUse) == 0 {
return true
@@ -190,7 +219,7 @@ func (f *DSStatFilter) UseStat(statName string) bool {
_, ok := f.statsToUse[statName]
return ok
}
- for statToUse, _ := range f.statsToUse {
+ for statToUse := range f.statsToUse {
if strings.Contains(statName, statToUse) {
return true
}
@@ -198,6 +227,7 @@ func (f *DSStatFilter) UseStat(statName string) bool {
return false
}
+// WithinStatHistoryMax returns whether the given history index is less than the max history of this filter.
func (f *DSStatFilter) WithinStatHistoryMax(n int) bool {
if f.historyCount == 0 {
return true
@@ -219,7 +249,7 @@ func NewDSStatFilter(params url.Values, dsTypes map[enum.DeliveryServiceName]enu
if len(params) > len(validParams) {
return nil, fmt.Errorf("invalid query parameters")
}
- for param, _ := range params {
+ for param := range params {
if _, ok := validParams[param]; !ok {
return nil, fmt.Errorf("invalid query parameter '%v'", param)
}
@@ -289,6 +319,7 @@ type PeerStateFilter struct {
cacheTypes map[enum.CacheName]enum.CacheType
}
+// UsePeer returns whether the given Traffic Monitor peer is in this filter.
func (f *PeerStateFilter) UsePeer(name enum.TrafficMonitorName) bool {
if _, inPeers := f.peersToUse[name]; len(f.peersToUse) != 0 && !inPeers {
return false
@@ -296,6 +327,7 @@ func (f *PeerStateFilter) UsePeer(name enum.TrafficMonitorName) bool {
return true
}
+// UseCache returns whether the given cache is in this filter.
func (f *PeerStateFilter) UseCache(name enum.CacheName) bool {
if f.cacheType != enum.CacheTypeInvalid && f.cacheTypes[name] != f.cacheType {
return false
@@ -309,7 +341,7 @@ func (f *PeerStateFilter) UseCache(name enum.CacheName) bool {
_, ok := f.cachesToUse[name]
return ok
}
- for cacheToUse, _ := range f.cachesToUse {
+ for cacheToUse := range f.cachesToUse {
if strings.Contains(string(name), string(cacheToUse)) {
return true
}
@@ -317,6 +349,7 @@ func (f *PeerStateFilter) UseCache(name enum.CacheName) bool {
return false
}
+// WithinStatHistoryMax returns whether the given history index is less than the max history of this filter.
func (f *PeerStateFilter) WithinStatHistoryMax(n int) bool {
if f.historyCount == 0 {
return true
@@ -339,7 +372,7 @@ func NewPeerStateFilter(params url.Values, cacheTypes map[enum.CacheName]enum.Ca
if len(params) > len(validParams) {
return nil, fmt.Errorf("invalid query parameters")
}
- for param, _ := range params {
+ for param := range params {
if _, ok := validParams[param]; !ok {
return nil, fmt.Errorf("invalid query parameter '%v'", param)
}
@@ -399,16 +432,16 @@ func NewPeerStateFilter(params url.Values, cacheTypes map[enum.CacheName]enum.Ca
}, nil
}
-// DataRequest takes an `http_server.DataRequest`, and the monitored data objects, and returns the appropriate response, and the status code.
+// DataRequest takes an `srvhttp.DataRequest`, and the monitored data objects, and returns the appropriate response, and the status code.
func DataRequest(
- req http_server.DataRequest,
+ req srvhttp.DataRequest,
opsConfig OpsConfigThreadsafe,
toSession towrap.ITrafficOpsSession,
localStates peer.CRStatesThreadsafe,
peerStates peer.CRStatesPeersThreadsafe,
combinedStates peer.CRStatesThreadsafe,
statHistory StatHistoryThreadsafe,
- dsStats DSStatsThreadsafe,
+ dsStats DSStatsReader,
events EventsThreadsafe,
staticAppData StaticAppData,
healthPollInterval time.Duration,
@@ -420,7 +453,8 @@ func DataRequest(
localCacheStatus CacheAvailableStatusThreadsafe,
lastStats LastStatsThreadsafe,
unpolledCaches UnpolledCachesThreadsafe,
-) (body []byte, responseCode int) {
+ monitorConfig TrafficMonitorConfigMapThreadsafe,
+) ([]byte, int) {
// handleErr takes an error, and the request type it came from, and logs. It is ok to call with a nil error, in which case this is a no-op.
handleErr := func(err error) {
@@ -431,7 +465,7 @@ func DataRequest(
log.Errorf("Request Error: %v\n", fmt.Errorf(req.Type.String()+": %v", err))
}
- // commonReturn takes the body, err, and the data request Type which has been processed. It logs and deals with any error, and returns the appropriate bytes and response code for the `http_server`.
+ // commonReturn takes the body, err, and the data request Type which has been processed. It logs and deals with any error, and returns the appropriate bytes and response code for the `srvhttp`.
commonReturn := func(body []byte, err error) ([]byte, int) {
if err == nil {
return body, http.StatusOK
@@ -445,9 +479,8 @@ func DataRequest(
return []byte("Service Unavailable"), http.StatusServiceUnavailable
}
- var err error
switch req.Type {
- case http_server.TRConfig:
+ case srvhttp.TRConfig:
cdnName := opsConfig.Get().CdnName
if toSession == nil {
return commonReturn(nil, fmt.Errorf("Unable to connect to Traffic Ops"))
@@ -455,61 +488,53 @@ func DataRequest(
if cdnName == "" {
return commonReturn(nil, fmt.Errorf("No CDN Configured"))
}
- return commonReturn(body, err)
- case http_server.TRStateDerived:
- body, err = peer.CrstatesMarshall(combinedStates.Get())
- return commonReturn(body, err)
- case http_server.TRStateSelf:
- body, err = peer.CrstatesMarshall(localStates.Get())
- return commonReturn(body, err)
- case http_server.CacheStats:
+ return commonReturn(toSession.CRConfigRaw(cdnName))
+ case srvhttp.TRStateDerived:
+ return commonReturn(peer.CrstatesMarshall(combinedStates.Get()))
+ case srvhttp.TRStateSelf:
+ return commonReturn(peer.CrstatesMarshall(localStates.Get()))
+ case srvhttp.CacheStats:
filter, err := NewCacheStatFilter(req.Parameters, toData.Get().ServerTypes)
if err != nil {
handleErr(err)
return []byte(err.Error()), http.StatusBadRequest
}
- body, err = cache.StatsMarshall(statHistory.Get(), filter, req.Parameters)
- return commonReturn(body, err)
- case http_server.DSStats:
+ return commonReturn(cache.StatsMarshall(statHistory.Get(), filter, req.Parameters))
+ case srvhttp.DSStats:
filter, err := NewDSStatFilter(req.Parameters, toData.Get().DeliveryServiceTypes)
if err != nil {
handleErr(err)
return []byte(err.Error()), http.StatusBadRequest
}
- body, err = json.Marshal(dsStats.Get().JSON(filter, req.Parameters)) // TODO marshall beforehand, for performance? (test to see how often requests are made)
- return commonReturn(body, err)
- case http_server.EventLog:
- body, err = json.Marshal(JSONEvents{Events: events.Get()})
- return commonReturn(body, err)
- case http_server.PeerStates:
+ // TODO marshall beforehand, for performance? (test to see how often requests are made)
+ return commonReturn(json.Marshal(dsStats.Get().JSON(filter, req.Parameters)))
+ case srvhttp.EventLog:
+ return commonReturn(json.Marshal(JSONEvents{Events: events.Get()}))
+ case srvhttp.PeerStates:
filter, err := NewPeerStateFilter(req.Parameters, toData.Get().ServerTypes)
if err != nil {
handleErr(err)
return []byte(err.Error()), http.StatusBadRequest
}
-
- body, err = json.Marshal(createApiPeerStates(peerStates.Get(), filter, req.Parameters))
- return commonReturn(body, err)
- case http_server.StatSummary:
+ return commonReturn(json.Marshal(createAPIPeerStates(peerStates.Get(), filter, req.Parameters)))
+ case srvhttp.StatSummary:
return nil, http.StatusNotImplemented
- case http_server.Stats:
- body, err = getStats(staticAppData, healthPollInterval, lastHealthDurations.Get(), fetchCount.Get(), healthIteration.Get(), errorCount.Get())
- return commonReturn(body, err)
- case http_server.ConfigDoc:
+ case srvhttp.Stats:
+ return commonReturn(getStats(staticAppData, healthPollInterval, lastHealthDurations.Get(), fetchCount.Get(), healthIteration.Get(), errorCount.Get()))
+ case srvhttp.ConfigDoc:
opsConfigCopy := opsConfig.Get()
// if the password is blank, leave it blank, so callers can see it's missing.
if opsConfigCopy.Password != "" {
opsConfigCopy.Password = "*****"
}
- body, err = json.Marshal(opsConfigCopy)
- return commonReturn(body, err)
- case http_server.APICacheCount: // TODO determine if this should use peerStates
+ return commonReturn(json.Marshal(opsConfigCopy))
+ case srvhttp.APICacheCount: // TODO determine if this should use peerStates
return []byte(strconv.Itoa(len(localStates.Get().Caches))), http.StatusOK
- case http_server.APICacheAvailableCount:
+ case srvhttp.APICacheAvailableCount:
return []byte(strconv.Itoa(cacheAvailableCount(localStates.Get().Caches))), http.StatusOK
- case http_server.APICacheDownCount:
- return []byte(strconv.Itoa(cacheDownCount(localStates.Get().Caches))), http.StatusOK
- case http_server.APIVersion:
+ case srvhttp.APICacheDownCount:
+ return []byte(strconv.Itoa(cacheDownCount(localStates.Get().Caches, monitorConfig.Get().TrafficServer))), http.StatusOK
+ case srvhttp.APIVersion:
s := "traffic_monitor-" + staticAppData.Version + "."
if len(staticAppData.GitRevision) > 6 {
s += staticAppData.GitRevision[:6]
@@ -517,13 +542,12 @@ func DataRequest(
s += staticAppData.GitRevision
}
return []byte(s), http.StatusOK
- case http_server.APITrafficOpsURI:
+ case srvhttp.APITrafficOpsURI:
return []byte(opsConfig.Get().Url), http.StatusOK
- case http_server.APICacheStates:
- body, err = json.Marshal(createCacheStatuses(toData.Get().ServerTypes, statHistory.Get(),
- lastHealthDurations.Get(), localStates.Get().Caches, lastStats.Get(), localCacheStatus))
- return commonReturn(body, err)
- case http_server.APIBandwidthKbps:
+ case srvhttp.APICacheStates:
+ return commonReturn(json.Marshal(createCacheStatuses(toData.Get().ServerTypes, statHistory.Get(),
+ lastHealthDurations.Get(), localStates.Get().Caches, lastStats.Get(), localCacheStatus)))
+ case srvhttp.APIBandwidthKbps:
serverTypes := toData.Get().ServerTypes
kbpsStats := lastStats.Get()
sum := float64(0.0)
@@ -534,7 +558,7 @@ func DataRequest(
sum += data.Bytes.PerSec / ds.BytesPerKilobit
}
return []byte(fmt.Sprintf("%f", sum)), http.StatusOK
- case http_server.APIBandwidthCapacityKbps:
+ case srvhttp.APIBandwidthCapacityKbps:
statHistory := statHistory.Get()
cap := int64(0)
for _, results := range statHistory {
@@ -601,7 +625,7 @@ func createCacheStatuses(
}
var kbps *float64
- lastStat, ok := lastStats.Caches[enum.CacheName(cacheName)]
+ lastStat, ok := lastStats.Caches[cacheName]
if !ok {
log.Warnf("cache not in last kbps cache %s\n", cacheName)
} else {
@@ -610,7 +634,7 @@ func createCacheStatuses(
}
var connections *int64
- connectionsVal, ok := conns[enum.CacheName(cacheName)]
+ connectionsVal, ok := conns[cacheName]
if !ok {
log.Warnf("cache not in connections %s\n", cacheName)
} else {
@@ -618,12 +642,12 @@ func createCacheStatuses(
}
var status *string
- statusVal, ok := localCacheStatus[enum.CacheName(cacheName)]
+ statusVal, ok := localCacheStatus[cacheName]
if !ok {
log.Warnf("cache not in statuses %s\n", cacheName)
} else {
statusString := statusVal.Status + " - "
- if localCacheStatus[enum.CacheName(cacheName)].Available {
+ if localCacheStatus[cacheName].Available {
statusString += "available"
} else {
statusString += "unavailable"
@@ -632,7 +656,7 @@ func createCacheStatuses(
}
cacheTypeStr := string(cacheType)
- statii[enum.CacheName(cacheName)] = CacheStatus{Type: &cacheTypeStr, LoadAverage: loadAverage, QueryTimeMilliseconds: queryTime, BandwidthKbps: kbps, ConnectionCount: connections, Status: status}
+ statii[cacheName] = CacheStatus{Type: &cacheTypeStr, LoadAverage: loadAverage, QueryTimeMilliseconds: queryTime, BandwidthKbps: kbps, ConnectionCount: connections, Status: status}
}
return statii
}
@@ -658,7 +682,8 @@ func createCacheConnections(statHistory map[enum.CacheName][]cache.Result) map[e
return conns
}
-func cacheDownCount(caches map[enum.CacheName]peer.IsAvailable) int {
+// cacheOfflineCount returns the total caches not available, including marked unavailable, status offline, and status admin_down
+func cacheOfflineCount(caches map[enum.CacheName]peer.IsAvailable) int {
count := 0
for _, available := range caches {
if !available.IsAvailable {
@@ -668,15 +693,26 @@ func cacheDownCount(caches map[enum.CacheName]peer.IsAvailable) int {
return count
}
+// cacheAvailableCount returns the total caches available, including marked available and status online
func cacheAvailableCount(caches map[enum.CacheName]peer.IsAvailable) int {
- return len(caches) - cacheDownCount(caches)
+ return len(caches) - cacheOfflineCount(caches)
+}
+
+// cacheOfflineCount returns the total reported caches marked down, excluding status offline and admin_down.
+func cacheDownCount(caches map[enum.CacheName]peer.IsAvailable, toServers map[string]to.TrafficServer) int {
+ count := 0
+ for cache, available := range caches {
+ if !available.IsAvailable && enum.CacheStatusFromString(toServers[string(cache)].Status) == enum.CacheStatusReported {
+ count++
+ }
+ }
+ return count
}
-func createApiPeerStates(peerStates map[enum.TrafficMonitorName]peer.Crstates, filter *PeerStateFilter, params url.Values) ApiPeerStates {
- apiPeerStates := ApiPeerStates{
- Peers: map[enum.TrafficMonitorName]map[enum.CacheName][]CacheState{},
- QueryParams: http_server.ParametersStr(params),
- DateStr: http_server.DateStr(time.Now()),
+func createAPIPeerStates(peerStates map[enum.TrafficMonitorName]peer.Crstates, filter *PeerStateFilter, params url.Values) APIPeerStates {
+ apiPeerStates := APIPeerStates{
+ CommonAPIData: srvhttp.GetCommonAPIData(params, time.Now()),
+ Peers: map[enum.TrafficMonitorName]map[enum.CacheName][]CacheState{},
}
for peer, state := range peerStates {
@@ -698,6 +734,7 @@ func createApiPeerStates(peerStates map[enum.TrafficMonitorName]peer.Crstates, f
return apiPeerStates
}
+// Stats contains statistics data about this running app. Designed to be returned via an API endpoint.
type Stats struct {
MaxMemoryMB uint64 `json:"Max Memory (MB)"`
GitRevision string `json:"git-revision"`
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/manager/dsstats.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/dsstats.go b/traffic_monitor/experimental/traffic_monitor/manager/dsstats.go
index ae273d8..23a3fef 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/dsstats.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/dsstats.go
@@ -1,31 +1,56 @@
package manager
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
- ds "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/deliveryservice"
- dsdata "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
+ ds "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservice"
+ dsdata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/deliveryservicedata"
"sync"
)
+// DSStatsThreadsafe wraps a deliveryservice.Stats object to be safe for multiple reader goroutines and a single writer.
type DSStatsThreadsafe struct {
dsStats *ds.Stats
m *sync.RWMutex
}
+// DSStatsReader permits reading of a dsdata.Stats object, but not writing. This is designed so a Stats object can safely be passed to multiple goroutines, without worry one may unsafely write.
type DSStatsReader interface {
Get() dsdata.StatsReadonly
}
+// NewDSStatsThreadsafe returns a deliveryservice.Stats object wrapped to be safe for multiple readers and a single writer.
func NewDSStatsThreadsafe() DSStatsThreadsafe {
s := ds.NewStats()
return DSStatsThreadsafe{m: &sync.RWMutex{}, dsStats: &s}
}
+// Get returns a Stats object safe for reading by multiple goroutines
func (o *DSStatsThreadsafe) Get() dsdata.StatsReadonly {
o.m.RLock()
defer o.m.RUnlock()
return *o.dsStats
}
+// Set sets the internal Stats object. This MUST NOT be called by multiple goroutines.
func (o *DSStatsThreadsafe) Set(newDsStats ds.Stats) {
o.m.Lock()
*o.dsStats = newDsStats
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/be5ab888/traffic_monitor/experimental/traffic_monitor/manager/events.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/events.go b/traffic_monitor/experimental/traffic_monitor/manager/events.go
index 19e4f5d..0a35783 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/events.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/events.go
@@ -1,11 +1,32 @@
package manager
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
import (
"sync"
- "github.com/Comcast/traffic_control/traffic_monitor/experimental/traffic_monitor/enum"
+ "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
)
+// Event represents an event change in aggregated data. For example, a cache being marked as unavailable.
type Event struct {
Index uint64 `json:"index"`
Time int64 `json:"time"`
@@ -16,6 +37,7 @@ type Event struct {
Available bool `json:"isAvailable"`
}
+// EventsThreadsafe provides safe access for multiple goroutines readers and a single writer to a stored Events slice.
type EventsThreadsafe struct {
events *[]Event
m *sync.RWMutex
@@ -25,17 +47,17 @@ type EventsThreadsafe struct {
func copyEvents(a []Event) []Event {
b := make([]Event, len(a), len(a))
- for i, v := range a {
- b[i] = v
- }
+ copy(b, a)
return b
}
+// NewEventsThreadsafe creates a new single-writer-multiple-reader Threadsafe object
func NewEventsThreadsafe(maxEvents uint64) EventsThreadsafe {
i := uint64(0)
return EventsThreadsafe{m: &sync.RWMutex{}, events: &[]Event{}, nextIndex: &i, max: maxEvents}
}
+// Get returns the internal slice of Events for reading. This MUST NOT be modified. If modification is necessary, copy the slice.
func (o *EventsThreadsafe) Get() []Event {
o.m.RLock()
defer o.m.RUnlock()