You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ne...@apache.org on 2017/01/23 17:27:26 UTC

[1/5] incubator-trafficcontrol git commit: [TC-109] Add default config entry for the event log.

Repository: incubator-trafficcontrol
Updated Branches:
  refs/heads/master bf0b08867 -> 7591165d8


[TC-109] Add default config entry for the event log.


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/963e4ddf
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/963e4ddf
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/963e4ddf

Branch: refs/heads/master
Commit: 963e4ddf98b04ec78bcec4d81cfe54bc339e6533
Parents: 0da2544
Author: Jeff Elsloo <je...@cable.comcast.com>
Authored: Fri Jan 20 16:10:53 2017 -0700
Committer: David Neuman <da...@gmail.com>
Committed: Mon Jan 23 10:25:41 2017 -0700

----------------------------------------------------------------------
 traffic_monitor/experimental/conf/traffic_monitor.cfg | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/963e4ddf/traffic_monitor/experimental/conf/traffic_monitor.cfg
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/conf/traffic_monitor.cfg b/traffic_monitor/experimental/conf/traffic_monitor.cfg
index 0ab06bb..f6698d1 100644
--- a/traffic_monitor/experimental/conf/traffic_monitor.cfg
+++ b/traffic_monitor/experimental/conf/traffic_monitor.cfg
@@ -10,6 +10,7 @@
 	"max_health_history": 5,
 	"health_flush_interval_ms": 20,
 	"stat_flush_interval_ms": 20,
+	"log_location_event": "null",
 	"log_location_error": "stderr",
 	"log_location_warning": "stdout",
 	"log_location_info": "null",


[2/5] incubator-trafficcontrol git commit: [TC-109] Enhance event logging to bring it more in line with the Java version of Traffic Monitor, plus a few bug fixes around management of peer states, the health protocol, and opening log files.

Posted by ne...@apache.org.
[TC-109] Enhance event logging to bring it more in line with the Java version of Traffic Monitor, plus a few bug fixes around management of peer states, the health protocol, and opening log files.


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/0da25442
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/0da25442
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/0da25442

Branch: refs/heads/master
Commit: 0da254428cc60a5846843f52788cd6fb1e6cbdda
Parents: a00660a
Author: Jeff Elsloo <je...@cable.comcast.com>
Authored: Fri Jan 20 16:04:06 2017 -0700
Committer: David Neuman <da...@gmail.com>
Committed: Mon Jan 23 10:25:41 2017 -0700

----------------------------------------------------------------------
 traffic_monitor/experimental/common/log/log.go  | 32 ++++---
 .../experimental/common/util/join.go            | 60 ++++++++++++++
 .../experimental/conf/traffic_monitor.cfg       |  1 +
 .../experimental/traffic_monitor/cache/data.go  | 11 ---
 .../traffic_monitor/config/config.go            | 10 +++
 .../traffic_monitor/deliveryservice/stat.go     | 17 +---
 .../experimental/traffic_monitor/enum/enum.go   |  8 ++
 .../traffic_monitor/health/cache_health.go      | 35 +++++---
 .../traffic_monitor/health/event.go             | 36 ++++++++
 .../traffic_monitor/manager/datarequest.go      | 12 ++-
 .../traffic_monitor/manager/healthresult.go     |  8 +-
 .../traffic_monitor/manager/manager.go          |  9 +-
 .../traffic_monitor/manager/peer.go             | 87 +++++++++++++++-----
 .../traffic_monitor/peer/crstates.go            | 44 ++++++++--
 .../experimental/traffic_monitor/peer/peer.go   | 14 ++--
 .../traffic_monitor/threadsafe/events.go        | 19 +++--
 .../traffic_monitor/traffic_monitor.go          | 22 +++--
 17 files changed, 315 insertions(+), 110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/common/log/log.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/common/log/log.go b/traffic_monitor/experimental/common/log/log.go
index 0fd33c9..b3b567b 100644
--- a/traffic_monitor/experimental/common/log/log.go
+++ b/traffic_monitor/experimental/common/log/log.go
@@ -9,9 +9,9 @@ package log
  * 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
@@ -20,7 +20,6 @@ package log
  * under the License.
  */
 
-
 import (
 	"fmt"
 	"io"
@@ -33,40 +32,49 @@ var (
 	Info    *log.Logger
 	Warning *log.Logger
 	Error   *log.Logger
+	Event   *log.Logger
 )
 
-func Init(errW, warnW, infoW, debugW io.Writer) {
+func Init(eventW, errW, warnW, infoW, debugW io.Writer) {
 	Debug = log.New(debugW, "DEBUG: ", log.Lshortfile)
 	Info = log.New(infoW, "INFO: ", log.Lshortfile)
 	Warning = log.New(warnW, "WARNING: ", log.Lshortfile)
 	Error = log.New(errW, "ERROR: ", log.Lshortfile)
+	Event = log.New(eventW, "", 0)
 }
 
 const timeFormat = time.RFC3339Nano
+const stackFrame = 3
 
 func Errorf(format string, v ...interface{}) {
-	Error.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
+	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
 }
 func Errorln(v ...interface{}) {
-	Error.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
+	Error.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
 }
 func Warnf(format string, v ...interface{}) {
-	Warning.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
+	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
 }
 func Warnln(v ...interface{}) {
-	Warning.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
+	Warning.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
 }
 func Infof(format string, v ...interface{}) {
-	Info.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
+	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
 }
 func Infoln(v ...interface{}) {
-	Info.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
+	Info.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
 }
 func Debugf(format string, v ...interface{}) {
-	Debug.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
+	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintf(format, v...))
 }
 func Debugln(v ...interface{}) {
-	Debug.Output(3, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
+	Debug.Output(stackFrame, time.Now().Format(timeFormat)+": "+fmt.Sprintln(v...))
+}
+
+// event log entries (TM event.log, TR access.log, etc)
+func Eventf(t time.Time, format string, v ...interface{}) {
+	// 1484001185.287 ...
+	Event.Printf("%.3f %s", float64(t.Unix())+(float64(t.Nanosecond())/1e9), fmt.Sprintf(format, v...))
 }
 
 // Close calls `Close()` on the given Closer, and logs any error. On error, the context is logged, followed by a colon, the error message, and a newline. This is primarily designed to be used in `defer`, for example, `defer log.Close(resp.Body, "readData fetching /foo/bar")`.

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/common/util/join.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/common/util/join.go b/traffic_monitor/experimental/common/util/join.go
new file mode 100644
index 0000000..d5b647b
--- /dev/null
+++ b/traffic_monitor/experimental/common/util/join.go
@@ -0,0 +1,60 @@
+package util
+
+/*
+ * 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"
+)
+
+func JoinErrorsString(errs []error) string {
+	joined := JoinErrors(errs)
+
+	if joined == nil {
+		return ""
+	}
+
+	return joined.Error()
+}
+
+func JoinErrors(errs []error) error {
+	return JoinErrorsSep(errs, "")
+}
+
+func JoinErrorsSep(errs []error, separator string) error {
+	if separator == "" {
+		separator = ", "
+	}
+
+	joinedErrors := ""
+
+	for _, err := range errs {
+		if err != nil {
+			joinedErrors += err.Error() + separator
+		}
+	}
+
+	if len(joinedErrors) == 0 {
+		return nil
+	}
+
+	joinedErrors = joinedErrors[:len(joinedErrors)-len(separator)] // strip trailing separator
+
+	return fmt.Errorf("%s", joinedErrors)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/conf/traffic_monitor.cfg
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/conf/traffic_monitor.cfg b/traffic_monitor/experimental/conf/traffic_monitor.cfg
index f2c25a0..0ab06bb 100644
--- a/traffic_monitor/experimental/conf/traffic_monitor.cfg
+++ b/traffic_monitor/experimental/conf/traffic_monitor.cfg
@@ -4,6 +4,7 @@
 	"monitor_config_polling_interval_ms": 5000,
 	"http_timeout_ms": 2000,
 	"peer_polling_interval_ms": 5000,
+	"peer_optimistic": true,
 	"max_events": 200,
 	"max_stat_history": 5,
 	"max_health_history": 5,

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/cache/data.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/cache/data.go b/traffic_monitor/experimental/traffic_monitor/cache/data.go
index e22e174..811babb 100644
--- a/traffic_monitor/experimental/traffic_monitor/cache/data.go
+++ b/traffic_monitor/experimental/traffic_monitor/cache/data.go
@@ -50,17 +50,6 @@ func (a AvailableStatuses) Copy() AvailableStatuses {
 	return b
 }
 
-// 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"`
-	Description string         `json:"description"`
-	Name        enum.CacheName `json:"name"`
-	Hostname    enum.CacheName `json:"hostname"`
-	Type        string         `json:"type"`
-	Available   bool           `json:"isAvailable"`
-}
-
 // ResultHistory is a map of cache names, to an array of result history from each cache.
 type ResultHistory map[enum.CacheName][]Result
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/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 24ba42a..1941ec6 100644
--- a/traffic_monitor/experimental/traffic_monitor/config/config.go
+++ b/traffic_monitor/experimental/traffic_monitor/config/config.go
@@ -46,6 +46,7 @@ type Config struct {
 	MonitorConfigPollingInterval time.Duration `json:"-"`
 	HTTPTimeout                  time.Duration `json:"-"`
 	PeerPollingInterval          time.Duration `json:"-"`
+	PeerOptimistic               bool          `json:"peer_optimistic"`
 	MaxEvents                    uint64        `json:"max_events"`
 	MaxStatHistory               uint64        `json:"max_stat_history"`
 	MaxHealthHistory             uint64        `json:"max_health_history"`
@@ -55,6 +56,7 @@ type Config struct {
 	LogLocationWarning           string        `json:"log_location_warning"`
 	LogLocationInfo              string        `json:"log_location_info"`
 	LogLocationDebug             string        `json:"log_location_debug"`
+	LogLocationEvent             string        `json:"log_location_event"`
 	ServeReadTimeout             time.Duration `json:"-"`
 	ServeWriteTimeout            time.Duration `json:"-"`
 	HealthToStatRatio            uint64        `json:"health_to_stat_ratio"`
@@ -69,6 +71,7 @@ var DefaultConfig = Config{
 	MonitorConfigPollingInterval: 5 * time.Second,
 	HTTPTimeout:                  2 * time.Second,
 	PeerPollingInterval:          5 * time.Second,
+	PeerOptimistic:               true,
 	MaxEvents:                    200,
 	MaxStatHistory:               5,
 	MaxHealthHistory:             5,
@@ -78,6 +81,7 @@ var DefaultConfig = Config{
 	LogLocationWarning:           LogLocationStdout,
 	LogLocationInfo:              LogLocationNull,
 	LogLocationDebug:             LogLocationNull,
+	LogLocationEvent:             LogLocationStdout,
 	ServeReadTimeout:             10 * time.Second,
 	ServeWriteTimeout:            10 * time.Second,
 	HealthToStatRatio:            4,
@@ -94,6 +98,7 @@ func (c *Config) MarshalJSON() ([]byte, error) {
 		MonitorConfigPollingIntervalMs uint64 `json:"monitor_config_polling_interval_ms"`
 		HTTPTimeoutMS                  uint64 `json:"http_timeout_ms"`
 		PeerPollingIntervalMs          uint64 `json:"peer_polling_interval_ms"`
+		PeerOptimistic                 bool   `json:"peer_optimistic"`
 		HealthFlushIntervalMs          uint64 `json:"health_flush_interval_ms"`
 		StatFlushIntervalMs            uint64 `json:"stat_flush_interval_ms"`
 		ServeReadTimeoutMs             uint64 `json:"serve_read_timeout_ms"`
@@ -105,6 +110,7 @@ func (c *Config) MarshalJSON() ([]byte, error) {
 		MonitorConfigPollingIntervalMs: uint64(c.MonitorConfigPollingInterval / time.Millisecond),
 		HTTPTimeoutMS:                  uint64(c.HTTPTimeout / time.Millisecond),
 		PeerPollingIntervalMs:          uint64(c.PeerPollingInterval / time.Millisecond),
+		PeerOptimistic:                 bool(true),
 		HealthFlushIntervalMs:          uint64(c.HealthFlushInterval / time.Millisecond),
 		StatFlushIntervalMs:            uint64(c.StatFlushInterval / time.Millisecond),
 		Alias:                          (*Alias)(c),
@@ -120,6 +126,7 @@ func (c *Config) UnmarshalJSON(data []byte) error {
 		MonitorConfigPollingIntervalMs *uint64 `json:"monitor_config_polling_interval_ms"`
 		HTTPTimeoutMS                  *uint64 `json:"http_timeout_ms"`
 		PeerPollingIntervalMs          *uint64 `json:"peer_polling_interval_ms"`
+		PeerOptimistic                 *bool   `json:"peer_optimistic"`
 		HealthFlushIntervalMs          *uint64 `json:"health_flush_interval_ms"`
 		StatFlushIntervalMs            *uint64 `json:"stat_flush_interval_ms"`
 		ServeReadTimeoutMs             *uint64 `json:"serve_read_timeout_ms"`
@@ -159,6 +166,9 @@ func (c *Config) UnmarshalJSON(data []byte) error {
 	if aux.ServeWriteTimeoutMs != nil {
 		c.ServeWriteTimeout = time.Duration(*aux.ServeWriteTimeoutMs) * time.Millisecond
 	}
+	if aux.PeerOptimistic != nil {
+		c.PeerOptimistic = *aux.PeerOptimistic
+	}
 	return nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/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 538eb02..3b7f35c 100644
--- a/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
+++ b/traffic_monitor/experimental/traffic_monitor/deliveryservice/stat.go
@@ -22,6 +22,7 @@ package deliveryservice
 import (
 	"fmt"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/util"
 	"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"
@@ -253,20 +254,6 @@ func addLastStat(lastData LastStatData, newStat int64, newStatTime time.Time) (L
 	return lastData, nil
 }
 
-func combineErrs(errs []error) error {
-	combinedErr := ""
-	for _, err := range errs {
-		if err != nil {
-			combinedErr += err.Error() + ", "
-		}
-	}
-	if len(combinedErr) == 0 {
-		return nil
-	}
-	combinedErr = combinedErr[:len(combinedErr)-2] // strip trailing ', '
-	return fmt.Errorf("%s", combinedErr)
-}
-
 func addLastStats(lastData LastStatsData, newStats dsdata.StatCacheStats, newStatsTime time.Time) (LastStatsData, error) {
 	errs := []error{nil, nil, nil, nil, nil}
 	lastData.Bytes, errs[0] = addLastStat(lastData.Bytes, newStats.OutBytes.Value, newStatsTime)
@@ -274,7 +261,7 @@ func addLastStats(lastData LastStatsData, newStats dsdata.StatCacheStats, newSta
 	lastData.Status3xx, errs[2] = addLastStat(lastData.Status3xx, newStats.Status3xx.Value, newStatsTime)
 	lastData.Status4xx, errs[3] = addLastStat(lastData.Status4xx, newStats.Status4xx.Value, newStatsTime)
 	lastData.Status5xx, errs[4] = addLastStat(lastData.Status5xx, newStats.Status5xx.Value, newStatsTime)
-	return lastData, combineErrs(errs)
+	return lastData, util.JoinErrors(errs)
 }
 
 func addLastStatsToStatCacheStats(s dsdata.StatCacheStats, l LastStatsData) dsdata.StatCacheStats {

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/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 733bba5..ce838ac 100644
--- a/traffic_monitor/experimental/traffic_monitor/enum/enum.go
+++ b/traffic_monitor/experimental/traffic_monitor/enum/enum.go
@@ -49,6 +49,14 @@ const (
 	CacheTypeInvalid = CacheType("")
 )
 
+func (c CacheName) String() string {
+	return string(c)
+}
+
+func (t TrafficMonitorName) String() string {
+	return string(t)
+}
+
 // String returns a string representation of this cache type.
 func (t CacheType) String() string {
 	switch t {

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/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 b57d143..7e9af51 100644
--- a/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
+++ b/traffic_monitor/experimental/traffic_monitor/health/cache_health.go
@@ -127,30 +127,39 @@ func cacheCapacityKbps(result cache.Result) int64 {
 func EvalCache(result cache.Result, mc *traffic_ops.TrafficMonitorConfigMap) (bool, string) {
 	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
 	kbpsThreshold, hasKbpsThreshold := getKbpsThreshold(params.HealthThresholdAvailableBandwidthInKbps)
 	queryTimeThreshold, hasQueryTimeThreshold := getQueryThreshold(int64(params.HealthThresholdQueryTime))
 
+	availability := "available"
+	if !result.Available {
+		availability = "unavailable"
+	}
+
 	switch {
+	case status == enum.CacheStatusInvalid:
+		log.Errorf("Cache %v got invalid status from Traffic Ops '%v' - treating as OFFLINE\n", result.ID, toServer.Status)
+		return false, getEventDescription(status, availability+"; invalid status")
 	case status == enum.CacheStatusAdminDown:
-		return false, "set to " + status.String()
+		return false, getEventDescription(status, availability)
 	case status == enum.CacheStatusOffline:
-		log.Errorf("Cache %v set to offline, but still polled\n", result.ID)
-		return false, "set to " + status.String()
+		log.Errorf("Cache %v set to OFFLINE, but still polled\n", result.ID)
+		return false, getEventDescription(status, availability)
 	case status == enum.CacheStatusOnline:
-		return true, "set to " + status.String()
+		return true, getEventDescription(status, availability)
 	case result.Error != nil:
-		return false, fmt.Sprintf("error: %v", result.Error)
+		return false, getEventDescription(status, fmt.Sprintf("%v", result.Error))
 	case result.Vitals.LoadAvg > params.HealthThresholdLoadAvg && params.HealthThresholdLoadAvg != 0:
-		return false, fmt.Sprintf("load average %f exceeds threshold %f", result.Vitals.LoadAvg, params.HealthThresholdLoadAvg)
-	case hasKbpsThreshold && result.Vitals.KbpsOut > cacheCapacityKbps(result)-kbpsThreshold:
-		return false, fmt.Sprintf("%dkbps exceeds max %dkbps", result.Vitals.KbpsOut, kbpsThreshold)
+		return false, getEventDescription(status, fmt.Sprintf("loadavg too high (%.5f > %.5f)", result.Vitals.LoadAvg, params.HealthThresholdLoadAvg))
+	case hasKbpsThreshold && cacheCapacityKbps(result)-result.Vitals.KbpsOut < kbpsThreshold:
+		return false, getEventDescription(status, fmt.Sprintf("availableBandwidthInKbps too low (%d < %d)", cacheCapacityKbps(result)-result.Vitals.KbpsOut, kbpsThreshold))
 	case hasQueryTimeThreshold && result.RequestTime > queryTimeThreshold:
-		return false, fmt.Sprintf("request time %v exceeds max %v", result.RequestTime, queryTimeThreshold)
+		return false, getEventDescription(status, fmt.Sprintf("queryTime too high (%.5f > %.5f)", float64(result.RequestTime.Nanoseconds())/1e6, float64(queryTimeThreshold.Nanoseconds())/1e6))
 	default:
-		return result.Available, "reported"
+		return result.Available, getEventDescription(status, availability)
 	}
 }
+
+func getEventDescription(status enum.CacheStatus, message string) string {
+	return fmt.Sprintf("%s - %s", status, message)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/health/event.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/health/event.go b/traffic_monitor/experimental/traffic_monitor/health/event.go
new file mode 100644
index 0000000..47563fa
--- /dev/null
+++ b/traffic_monitor/experimental/traffic_monitor/health/event.go
@@ -0,0 +1,36 @@
+package health
+
+/*
+ * 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 (
+	"time"
+)
+
+// Event represents an event change in aggregated data. For example, a cache being marked as unavailable.
+type Event struct {
+	Time        time.Time `json:"-"`
+	Index       uint64    `json:"index"`
+	Unix        int64     `json:"time"`
+	Description string    `json:"description"`
+	Name        string    `json:"name"`
+	Hostname    string    `json:"hostname"`
+	Type        string    `json:"type"`
+	Available   bool      `json:"isAvailable"`
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/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 b3beee8..e4a35ed 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/datarequest.go
@@ -35,6 +35,7 @@ import (
 	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/health"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/srvhttp"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/threadsafe"
@@ -45,7 +46,7 @@ import (
 
 // JSONEvents represents the structure we wish to serialize to JSON, for Events.
 type JSONEvents struct {
-	Events []cache.Event `json:"events"`
+	Events []health.Event `json:"events"`
 }
 
 // CacheState represents the available state of a cache.
@@ -612,7 +613,7 @@ func srvPeerStates(params url.Values, errorCount threadsafe.Uint, path string, t
 		HandleErr(errorCount, path, err)
 		return []byte(err.Error()), http.StatusBadRequest
 	}
-	bytes, err := json.Marshal(createAPIPeerStates(peerStates.Get(), filter, params))
+	bytes, err := json.Marshal(createAPIPeerStates(peerStates.GetCrstates(), filter, params))
 	return WrapErrCode(errorCount, path, bytes, err)
 }
 
@@ -965,11 +966,16 @@ func createCacheStatuses(
 			log.Warnf("cache not in statuses %s\n", cacheName)
 		} else {
 			statusString := statusVal.Status + " - "
-			if statusVal.Available {
+
+			// this should match the event string, use as the default if possible
+			if statusVal.Why != "" {
+				statusString = statusVal.Why
+			} else if statusVal.Available {
 				statusString += "available"
 			} else {
 				statusString += fmt.Sprintf("unavailable (%s)", statusVal.Why)
 			}
+
 			status = &statusString
 		}
 

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/manager/healthresult.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/healthresult.go b/traffic_monitor/experimental/traffic_monitor/manager/healthresult.go
index 9c150e4..ed9f9fc 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/healthresult.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/healthresult.go
@@ -86,9 +86,9 @@ func StartHealthResultManager(
 	fetchCount threadsafe.Uint,
 	errorCount threadsafe.Uint,
 	cfg config.Config,
-) (DurationMapThreadsafe, threadsafe.Events, threadsafe.CacheAvailableStatus, threadsafe.ResultHistory) {
+	events threadsafe.Events,
+) (DurationMapThreadsafe, threadsafe.CacheAvailableStatus, threadsafe.ResultHistory) {
 	lastHealthDurations := NewDurationMapThreadsafe()
-	events := threadsafe.NewEvents(cfg.MaxEvents)
 	localCacheStatus := threadsafe.NewCacheAvailableStatus()
 	healthHistory := threadsafe.NewResultHistory()
 	go healthResultManagerListen(
@@ -106,7 +106,7 @@ func StartHealthResultManager(
 		localCacheStatus,
 		cfg,
 	)
-	return lastHealthDurations, events, localCacheStatus, healthHistory
+	return lastHealthDurations, localCacheStatus, healthHistory
 }
 
 func healthResultManagerListen(
@@ -235,7 +235,7 @@ func processHealthResult(
 		isAvailable, whyAvailable := health.EvalCache(healthResult, &monitorConfigCopy)
 		if available, ok := localStates.GetCache(healthResult.ID); !ok || available.IsAvailable != isAvailable {
 			log.Infof("Changing state for %s was: %t now: %t because %s error: %v", healthResult.ID, prevResult.Available, isAvailable, whyAvailable, healthResult.Error)
-			events.Add(cache.Event{Time: time.Now().Unix(), Description: whyAvailable, Name: healthResult.ID, Hostname: healthResult.ID, Type: toDataCopy.ServerTypes[healthResult.ID].String(), Available: isAvailable})
+			events.Add(health.Event{Time: healthResult.Time, Unix: healthResult.Time.Unix(), Description: whyAvailable, Name: healthResult.ID.String(), Hostname: healthResult.ID.String(), Type: toDataCopy.ServerTypes[healthResult.ID].String(), Available: isAvailable})
 		}
 
 		localCacheStatus[healthResult.ID] = cache.AvailableStatus{

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/manager/manager.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/manager.go b/traffic_monitor/experimental/traffic_monitor/manager/manager.go
index e794b7c..26ebb37 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/manager.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/manager.go
@@ -63,6 +63,7 @@ func Start(opsConfigFile string, cfg config.Config, staticAppData StaticAppData)
 	// TODO investigate whether a unique client per cache to be polled is faster
 	sharedClient := &http.Client{
 		Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
+		Timeout:   cfg.HTTPTimeout,
 	}
 
 	localStates := peer.NewCRStatesThreadsafe()     // this is the local state as discoverer by this traffic_monitor
@@ -86,6 +87,8 @@ func Start(opsConfigFile string, cfg config.Config, staticAppData StaticAppData)
 	go cacheStatPoller.Poll()
 	go peerPoller.Poll()
 
+	events := threadsafe.NewEvents(cfg.MaxEvents)
+
 	cachesChanged := make(chan struct{})
 
 	monitorConfig := StartMonitorConfigManager(
@@ -103,6 +106,9 @@ func Start(opsConfigFile string, cfg config.Config, staticAppData StaticAppData)
 		peerHandler.ResultChannel,
 		localStates,
 		peerStates,
+		events,
+		cfg.PeerOptimistic,
+		toData,
 	)
 
 	statInfoHistory, statResultHistory, statMaxKbpses, _, lastKbpsStats, dsStats, unpolledCaches := StartStatHistoryManager(
@@ -116,7 +122,7 @@ func Start(opsConfigFile string, cfg config.Config, staticAppData StaticAppData)
 		monitorConfig,
 	)
 
-	lastHealthDurations, events, localCacheStatus, healthHistory := StartHealthResultManager(
+	lastHealthDurations, localCacheStatus, healthHistory := StartHealthResultManager(
 		cacheHealthHandler.ResultChannel,
 		toData,
 		localStates,
@@ -126,6 +132,7 @@ func Start(opsConfigFile string, cfg config.Config, staticAppData StaticAppData)
 		fetchCount,
 		errorCount,
 		cfg,
+		events,
 	)
 
 	StartOpsConfigManager(

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/manager/peer.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/manager/peer.go b/traffic_monitor/experimental/traffic_monitor/manager/peer.go
index 5a94e70..2f8cbdb 100644
--- a/traffic_monitor/experimental/traffic_monitor/manager/peer.go
+++ b/traffic_monitor/experimental/traffic_monitor/manager/peer.go
@@ -20,11 +20,18 @@ package manager
  */
 
 import (
+	"fmt"
 	"sort"
+	"strings"
+	"time"
 
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/util"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/enum"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/health"
 	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/peer"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/threadsafe"
+	todata "github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/trafficopsdata"
 )
 
 // StartPeerManager listens for peer results, and when it gets one, it adds it to the peerStates list, and optimistically combines the good results into combinedStates
@@ -32,43 +39,83 @@ func StartPeerManager(
 	peerChan <-chan peer.Result,
 	localStates peer.CRStatesThreadsafe,
 	peerStates peer.CRStatesPeersThreadsafe,
+	events threadsafe.Events,
+	peerOptimistic bool,
+	toData todata.TODataThreadsafe,
 ) peer.CRStatesThreadsafe {
 	combinedStates := peer.NewCRStatesThreadsafe()
+	overrideMap := map[enum.CacheName]bool{}
+
 	go func() {
-		for crStatesResult := range peerChan {
-			peerStates.Set(crStatesResult.ID, crStatesResult.PeerStats)
-			combineCrStates(peerStates.Get(), localStates.Get(), combinedStates)
-			crStatesResult.PollFinished <- crStatesResult.PollID
+		for peerResult := range peerChan {
+			comparePeerState(events, peerResult, peerStates)
+			peerStates.Set(peerResult)
+			combineCrStates(events, peerOptimistic, peerStates, localStates.Get(), combinedStates, overrideMap, toData)
+			peerResult.PollFinished <- peerResult.PollID
 		}
 	}()
 	return combinedStates
 }
 
+func comparePeerState(events threadsafe.Events, result peer.Result, peerStates peer.CRStatesPeersThreadsafe) {
+	if result.Available != peerStates.GetPeerAvailability(result.ID) {
+		events.Add(health.Event{Time: result.Time, Unix: result.Time.Unix(), Description: util.JoinErrorsString(result.Errors), Name: result.ID.String(), Hostname: result.ID.String(), Type: "Peer", Available: result.Available})
+	}
+}
+
 // TODO JvD: add deliveryservice stuff
-func combineCrStates(peerStates map[enum.TrafficMonitorName]peer.Crstates, localStates peer.Crstates, combinedStates peer.CRStatesThreadsafe) {
+func combineCrStates(events threadsafe.Events, peerOptimistic bool, peerStates peer.CRStatesPeersThreadsafe, localStates peer.Crstates, combinedStates peer.CRStatesThreadsafe, overrideMap map[enum.CacheName]bool, toData todata.TODataThreadsafe) {
+	toDataCopy := toData.Get()
+
 	for cacheName, localCacheState := range localStates.Caches { // localStates gets pruned when servers are disabled, it's the source of truth
-		downVotes := 0 // TODO JvD: change to use parameter when deciding to be optimistic or pessimistic.
+		var overrideCondition string
 		available := false
+		override := overrideMap[cacheName]
+
 		if localCacheState.IsAvailable {
-			// log.Infof(cacheName, " is available locally - setting to IsAvailable: true")
 			available = true // we don't care about the peers, we got a "good one", and we're optimistic
-		} else {
-			downVotes++ // localStates says it's not happy
-			for _, peerCrStates := range peerStates {
-				if peerCrStates.Caches[cacheName].IsAvailable {
-					// log.Infoln(cacheName, "- locally we think it's down, but", peerName, "says IsAvailable: ", peerCrStates.Caches[cacheName].IsAvailable, "trusting the peer.")
-					available = true // we don't care about the peers, we got a "good one", and we're optimistic
-					break            // one peer that thinks we're good is all we need.
+
+			if override {
+				overrideCondition = "cleared; healthy locally"
+				overrideMap[cacheName] = false
+			}
+		} else if peerOptimistic {
+			if !peerStates.HasAvailablePeers() {
+				if override {
+					overrideCondition = "irrelevant; no peers online"
+					overrideMap[cacheName] = false
+				}
+			} else {
+				onlineOnPeers := make([]string, 0)
+
+				for peer, peerCrStates := range peerStates.GetCrstates() {
+					if peerStates.GetPeerAvailability(peer) {
+						if peerCrStates.Caches[cacheName].IsAvailable {
+							onlineOnPeers = append(onlineOnPeers, peer.String())
+						}
+					}
+				}
+
+				if len(onlineOnPeers) > 0 {
+					available = true
+
+					if !override {
+						overrideCondition = fmt.Sprintf("detected; healthy on (at least) %s", strings.Join(onlineOnPeers, ", "))
+						overrideMap[cacheName] = true
+					}
 				} else {
-					// log.Infoln(cacheName, "- locally we think it's down, and", peerName, "says IsAvailable: ", peerCrStates.Caches[cacheName].IsAvailable, "down voting")
-					downVotes++ // peerStates for this peer doesn't like it
+					if override {
+						overrideCondition = "irrelevant; not online on any peers"
+						overrideMap[cacheName] = false
+					}
 				}
 			}
 		}
-		if downVotes > len(peerStates) {
-			// log.Infoln(cacheName, "-", downVotes, "down votes, setting to IsAvailable: false")
-			available = false
+
+		if overrideCondition != "" {
+			events.Add(health.Event{Time: time.Now(), Unix: time.Now().Unix(), Description: fmt.Sprintf("Health protocol override condition %s", overrideCondition), Name: cacheName.String(), Hostname: cacheName.String(), Type: toDataCopy.ServerTypes[cacheName].String(), Available: available})
 		}
+
 		combinedStates.SetCache(cacheName, peer.IsAvailable{IsAvailable: available})
 	}
 
@@ -79,7 +126,7 @@ func combineCrStates(peerStates map[enum.TrafficMonitorName]peer.Crstates, local
 		}
 		deliveryService.DisabledLocations = localDeliveryService.DisabledLocations
 
-		for peerName, iPeerStates := range peerStates {
+		for peerName, iPeerStates := range peerStates.GetCrstates() {
 			peerDeliveryService, ok := iPeerStates.Deliveryservice[deliveryServiceName]
 			if !ok {
 				log.Warnf("local delivery service %s not found in peer %s\n", deliveryServiceName, peerName)

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/crstates.go b/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
index ef5176a..cac90e1 100644
--- a/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
+++ b/traffic_monitor/experimental/traffic_monitor/peer/crstates.go
@@ -177,17 +177,18 @@ func (t *CRStatesThreadsafe) DeleteDeliveryService(name enum.DeliveryServiceName
 // CRStatesPeersThreadsafe provides safe access for multiple goroutines to read a map of Traffic Monitor peers to their returned Crstates, with a single goroutine writer.
 // This could be made lock-free, if the performance was necessary
 type CRStatesPeersThreadsafe struct {
-	crStates map[enum.TrafficMonitorName]Crstates
-	m        *sync.RWMutex
+	crStates   map[enum.TrafficMonitorName]Crstates
+	peerStates map[enum.TrafficMonitorName]bool
+	m          *sync.RWMutex
 }
 
 // NewCRStatesPeersThreadsafe creates a new CRStatesPeers object safe for multiple goroutine readers and a single writer.
 func NewCRStatesPeersThreadsafe() CRStatesPeersThreadsafe {
-	return CRStatesPeersThreadsafe{m: &sync.RWMutex{}, crStates: map[enum.TrafficMonitorName]Crstates{}}
+	return CRStatesPeersThreadsafe{m: &sync.RWMutex{}, crStates: map[enum.TrafficMonitorName]Crstates{}, peerStates: map[enum.TrafficMonitorName]bool{}}
 }
 
-// Get returns the internal Traffic Monitor peer Crstates data. This MUST NOT be modified.
-func (t *CRStatesPeersThreadsafe) Get() map[enum.TrafficMonitorName]Crstates {
+// GetCrstates returns the internal Traffic Monitor peer Crstates data. This MUST NOT be modified.
+func (t *CRStatesPeersThreadsafe) GetCrstates() map[enum.TrafficMonitorName]Crstates {
 	t.m.RLock()
 	m := map[enum.TrafficMonitorName]Crstates{}
 	for k, v := range t.crStates {
@@ -197,9 +198,36 @@ func (t *CRStatesPeersThreadsafe) Get() map[enum.TrafficMonitorName]Crstates {
 	return m
 }
 
-// Set sets the internal Traffic Monitor peer Crstates data. This MUST NOT be called by multiple goroutines.
-func (t *CRStatesPeersThreadsafe) Set(peerName enum.TrafficMonitorName, peerState Crstates) {
+// GetPeerAvailability returns the state of the given peer
+func (t *CRStatesPeersThreadsafe) GetPeerAvailability(peer enum.TrafficMonitorName) bool {
+	t.m.RLock()
+	availability := t.peerStates[peer]
+	t.m.RUnlock()
+	return availability
+}
+
+// HasAvailablePeers returns true if at least one peer is online
+func (t *CRStatesPeersThreadsafe) HasAvailablePeers() bool {
+	availablePeers := false
+
+	t.m.RLock()
+
+	for _, available := range t.peerStates {
+		if available {
+			availablePeers = true
+			break
+		}
+	}
+
+	t.m.RUnlock()
+
+	return availablePeers
+}
+
+// Set sets the internal Traffic Monitor peer state and Crstates data. This MUST NOT be called by multiple goroutines.
+func (t *CRStatesPeersThreadsafe) Set(result Result) {
 	t.m.Lock()
-	t.crStates[peerName] = peerState
+	t.crStates[result.ID] = result.PeerStates
+	t.peerStates[result.ID] = result.Available
 	t.m.Unlock()
 }

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/peer/peer.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/peer/peer.go b/traffic_monitor/experimental/traffic_monitor/peer/peer.go
index c8958c1..66755f8 100644
--- a/traffic_monitor/experimental/traffic_monitor/peer/peer.go
+++ b/traffic_monitor/experimental/traffic_monitor/peer/peer.go
@@ -8,9 +8,9 @@ package peer
  * 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
@@ -19,7 +19,6 @@ package peer
  * under the License.
  */
 
-
 import (
 	"encoding/json"
 	"io"
@@ -44,9 +43,10 @@ type Result struct {
 	ID           enum.TrafficMonitorName
 	Available    bool
 	Errors       []error
-	PeerStats    Crstates
+	PeerStates   Crstates
 	PollID       uint64
 	PollFinished chan<- uint64
+	Time         time.Time
 }
 
 // Handle handles a response from a polled Traffic Monitor peer, parsing the data and forwarding it to the ResultChannel.
@@ -57,6 +57,7 @@ func (handler Handler) Handle(id string, r io.Reader, reqTime time.Duration, err
 		Errors:       []error{},
 		PollID:       pollID,
 		PollFinished: pollFinished,
+		Time:         time.Now(),
 	}
 
 	if err != nil {
@@ -65,10 +66,11 @@ func (handler Handler) Handle(id string, r io.Reader, reqTime time.Duration, err
 
 	if r != nil {
 		dec := json.NewDecoder(r)
+		err = dec.Decode(&result.PeerStates)
 
-		if err := dec.Decode(&result.PeerStats); err == io.EOF {
+		if err == nil {
 			result.Available = true
-		} else if err != nil {
+		} else {
 			result.Errors = append(result.Errors, err)
 		}
 	}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/threadsafe/events.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/threadsafe/events.go b/traffic_monitor/experimental/traffic_monitor/threadsafe/events.go
index 6f92481..fe78ba5 100644
--- a/traffic_monitor/experimental/traffic_monitor/threadsafe/events.go
+++ b/traffic_monitor/experimental/traffic_monitor/threadsafe/events.go
@@ -22,19 +22,20 @@ package threadsafe
 import (
 	"sync"
 
-	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/cache"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/common/log"
+	"github.com/apache/incubator-trafficcontrol/traffic_monitor/experimental/traffic_monitor/health"
 )
 
 // Events provides safe access for multiple goroutines readers and a single writer to a stored Events slice.
 type Events struct {
-	events    *[]cache.Event
+	events    *[]health.Event
 	m         *sync.RWMutex
 	nextIndex *uint64
 	max       uint64
 }
 
-func copyEvents(a []cache.Event) []cache.Event {
-	b := make([]cache.Event, len(a), len(a))
+func copyEvents(a []health.Event) []health.Event {
+	b := make([]health.Event, len(a), len(a))
 	copy(b, a)
 	return b
 }
@@ -42,21 +43,23 @@ func copyEvents(a []cache.Event) []cache.Event {
 // NewEvents creates a new single-writer-multiple-reader Threadsafe object
 func NewEvents(maxEvents uint64) Events {
 	i := uint64(0)
-	return Events{m: &sync.RWMutex{}, events: &[]cache.Event{}, nextIndex: &i, max: maxEvents}
+	return Events{m: &sync.RWMutex{}, events: &[]health.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 *Events) Get() []cache.Event {
+func (o *Events) Get() []health.Event {
 	o.m.RLock()
 	defer o.m.RUnlock()
 	return *o.events
 }
 
 // Add adds the given event. This is threadsafe for one writer, multiple readers. This MUST NOT be called by multiple threads, as it non-atomically fetches and adds.
-func (o *Events) Add(e cache.Event) {
+func (o *Events) Add(e health.Event) {
+	// host="hostname", type=EDGE, available=true, msg="REPORTED - available"
+	log.Eventf(e.Time, "host=\"%s\", type=%s, available=%t, msg=\"%s\"", e.Hostname, e.Type, e.Available, e.Description)
 	events := copyEvents(*o.events)
 	e.Index = *o.nextIndex
-	events = append([]cache.Event{e}, events...)
+	events = append([]health.Event{e}, events...)
 	if len(events) > int(o.max) {
 		events = (events)[:o.max-1]
 	}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/0da25442/traffic_monitor/experimental/traffic_monitor/traffic_monitor.go
----------------------------------------------------------------------
diff --git a/traffic_monitor/experimental/traffic_monitor/traffic_monitor.go b/traffic_monitor/experimental/traffic_monitor/traffic_monitor.go
index 671e10e..f97cf3d 100644
--- a/traffic_monitor/experimental/traffic_monitor/traffic_monitor.go
+++ b/traffic_monitor/experimental/traffic_monitor/traffic_monitor.go
@@ -92,27 +92,31 @@ func getLogWriter(location string) (io.Writer, error) {
 	case config.LogLocationNull:
 		return ioutil.Discard, nil
 	default:
-		return os.Open(location)
+		return os.OpenFile(location, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
 	}
 }
-func getLogWriters(errLoc, warnLoc, infoLoc, debugLoc string) (io.Writer, io.Writer, io.Writer, io.Writer, error) {
+func getLogWriters(eventLoc, errLoc, warnLoc, infoLoc, debugLoc string) (io.Writer, io.Writer, io.Writer, io.Writer, io.Writer, error) {
+	eventW, err := getLogWriter(eventLoc)
+	if err != nil {
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log event writer %v: %v", eventLoc, err)
+	}
 	errW, err := getLogWriter(errLoc)
 	if err != nil {
-		return nil, nil, nil, nil, fmt.Errorf("getting log error writer %v: %v", errLoc, err)
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log error writer %v: %v", errLoc, err)
 	}
 	warnW, err := getLogWriter(warnLoc)
 	if err != nil {
-		return nil, nil, nil, nil, fmt.Errorf("getting log warning writer %v: %v", warnLoc, err)
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log warning writer %v: %v", warnLoc, err)
 	}
 	infoW, err := getLogWriter(infoLoc)
 	if err != nil {
-		return nil, nil, nil, nil, fmt.Errorf("getting log info writer %v: %v", infoLoc, err)
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log info writer %v: %v", infoLoc, err)
 	}
 	debugW, err := getLogWriter(debugLoc)
 	if err != nil {
-		return nil, nil, nil, nil, fmt.Errorf("getting log debug writer %v: %v", debugLoc, err)
+		return nil, nil, nil, nil, nil, fmt.Errorf("getting log debug writer %v: %v", debugLoc, err)
 	}
-	return errW, warnW, infoW, debugW, nil
+	return eventW, errW, warnW, infoW, debugW, nil
 }
 
 func main() {
@@ -140,12 +144,12 @@ func main() {
 		os.Exit(1)
 	}
 
-	errW, warnW, infoW, debugW, err := getLogWriters(cfg.LogLocationError, cfg.LogLocationWarning, cfg.LogLocationInfo, cfg.LogLocationDebug)
+	eventW, errW, warnW, infoW, debugW, err := getLogWriters(cfg.LogLocationEvent, cfg.LogLocationError, cfg.LogLocationWarning, cfg.LogLocationInfo, cfg.LogLocationDebug)
 	if err != nil {
 		fmt.Printf("Error starting service: failed to create log writers: %v\n", err)
 		os.Exit(1)
 	}
-	log.Init(errW, warnW, infoW, debugW)
+	log.Init(eventW, errW, warnW, infoW, debugW)
 
 	log.Infof("Starting with config %+v\n", cfg)
 



[4/5] incubator-trafficcontrol git commit: remove duplicate license and repeated code

Posted by ne...@apache.org.
remove duplicate license and repeated code


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/b3e3344f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/b3e3344f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/b3e3344f

Branch: refs/heads/master
Commit: b3e3344f60a7dffe2fe606aee5895b8ececbf62c
Parents: 3aa3c89
Author: Dan Kirkwood <da...@gmail.com>
Authored: Fri Jan 20 20:57:13 2017 +0000
Committer: David Neuman <da...@gmail.com>
Committed: Mon Jan 23 10:26:38 2017 -0700

----------------------------------------------------------------------
 traffic_ops/app/lib/Schema/Result/Server.pm     | 492 -------------------
 .../app/lib/Schema/Result/SteeringView.pm       |  22 -
 2 files changed, 514 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b3e3344f/traffic_ops/app/lib/Schema/Result/Server.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/Schema/Result/Server.pm b/traffic_ops/app/lib/Schema/Result/Server.pm
index 927ddaf..33a4dff 100644
--- a/traffic_ops/app/lib/Schema/Result/Server.pm
+++ b/traffic_ops/app/lib/Schema/Result/Server.pm
@@ -503,497 +503,5 @@ __PACKAGE__->belongs_to(
 
 # Created by DBIx::Class::Schema::Loader v0.07046 @ 2016-11-18 22:45:19
 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:3f6+Y6k32Vn3CDG7R7uToQ
-# These lines were loaded from '/Users/drichard/projects/github.com/traffic_control/traffic_ops/app/lib/Schema/Result/Server.pm' found in @INC.
-# They are now part of the custom portion of this file
-# for you to hand-edit.  If you do not either delete
-# this section or remove that file from @INC, this section
-# will be repeated redundantly when you re-create this
-# file again via Loader!  See skip_load_external to disable
-# this feature.
 
-use utf8;
-package Schema::Result::Server;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Schema::Result::Server
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<server>
-
-=cut
-
-__PACKAGE__->table("server");
-
-=head1 ACCESSORS
-
-=head2 id
-
-  data_type: 'integer'
-  is_auto_increment: 1
-  is_nullable: 0
-
-=head2 host_name
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 63
-
-=head2 domain_name
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 63
-
-=head2 tcp_port
-
-  data_type: 'integer'
-  extra: {unsigned => 1}
-  is_nullable: 1
-
-=head2 xmpp_id
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 256
-
-=head2 xmpp_passwd
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 interface_name
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 45
-
-=head2 ip_address
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 45
-
-=head2 ip_netmask
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 45
-
-=head2 ip_gateway
-
-  data_type: 'varchar'
-  is_nullable: 0
-  size: 45
-
-=head2 ip6_address
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 50
-
-=head2 ip6_gateway
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 50
-
-=head2 interface_mtu
-
-  data_type: 'integer'
-  default_value: 9000
-  is_nullable: 0
-
-=head2 phys_location
-
-  data_type: 'integer'
-  is_foreign_key: 1
-  is_nullable: 0
-
-=head2 rack
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 64
-
-=head2 cachegroup
-
-  data_type: 'integer'
-  default_value: 0
-  is_foreign_key: 1
-  is_nullable: 0
-
-=head2 type
-
-  data_type: 'integer'
-  is_foreign_key: 1
-  is_nullable: 0
-
-=head2 status
-
-  data_type: 'integer'
-  is_foreign_key: 1
-  is_nullable: 0
-
-=head2 upd_pending
-
-  data_type: 'tinyint'
-  default_value: 0
-  is_nullable: 0
-
-=head2 profile
-
-  data_type: 'integer'
-  is_foreign_key: 1
-  is_nullable: 0
-
-=head2 mgmt_ip_address
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 mgmt_ip_netmask
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 mgmt_ip_gateway
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 ilo_ip_address
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 ilo_ip_netmask
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 ilo_ip_gateway
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 ilo_username
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 ilo_password
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 45
-
-=head2 router_host_name
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 256
-
-=head2 router_port_name
-
-  data_type: 'varchar'
-  is_nullable: 1
-  size: 256
-
-=head2 last_updated
-
-  data_type: 'timestamp'
-  datetime_undef_if_invalid: 1
-  default_value: current_timestamp
-  is_nullable: 1
-
-=cut
-
-__PACKAGE__->add_columns(
-  "id",
-  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
-  "host_name",
-  { data_type => "varchar", is_nullable => 0, size => 63 },
-  "domain_name",
-  { data_type => "varchar", is_nullable => 0, size => 63 },
-  "tcp_port",
-  { data_type => "integer", extra => { unsigned => 1 }, is_nullable => 1 },
-  "xmpp_id",
-  { data_type => "varchar", is_nullable => 1, size => 256 },
-  "xmpp_passwd",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "interface_name",
-  { data_type => "varchar", is_nullable => 0, size => 45 },
-  "ip_address",
-  { data_type => "varchar", is_nullable => 0, size => 45 },
-  "ip_netmask",
-  { data_type => "varchar", is_nullable => 0, size => 45 },
-  "ip_gateway",
-  { data_type => "varchar", is_nullable => 0, size => 45 },
-  "ip6_address",
-  { data_type => "varchar", is_nullable => 1, size => 50 },
-  "ip6_gateway",
-  { data_type => "varchar", is_nullable => 1, size => 50 },
-  "interface_mtu",
-  { data_type => "integer", default_value => 9000, is_nullable => 0 },
-  "phys_location",
-  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
-  "rack",
-  { data_type => "varchar", is_nullable => 1, size => 64 },
-  "cachegroup",
-  {
-    data_type      => "integer",
-    default_value  => 0,
-    is_foreign_key => 1,
-    is_nullable    => 0,
-  },
-  "type",
-  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
-  "status",
-  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
-  "upd_pending",
-  { data_type => "tinyint", default_value => 0, is_nullable => 0 },
-  "profile",
-  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
-  "mgmt_ip_address",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "mgmt_ip_netmask",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "mgmt_ip_gateway",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "ilo_ip_address",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "ilo_ip_netmask",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "ilo_ip_gateway",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "ilo_username",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "ilo_password",
-  { data_type => "varchar", is_nullable => 1, size => 45 },
-  "router_host_name",
-  { data_type => "varchar", is_nullable => 1, size => 256 },
-  "router_port_name",
-  { data_type => "varchar", is_nullable => 1, size => 256 },
-  "last_updated",
-  {
-    data_type => "timestamp",
-    datetime_undef_if_invalid => 1,
-    default_value => \"current_timestamp",
-    is_nullable => 1,
-  },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</id>
-
-=item * L</cachegroup>
-
-=item * L</type>
-
-=item * L</status>
-
-=item * L</profile>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("id", "cachegroup", "type", "status", "profile");
-
-=head2 C<se_id_UNIQUE>
-
-=over 4
-
-=item * L</id>
-
-=back
-
-=cut
-
-__PACKAGE__->add_unique_constraint("se_id_UNIQUE", ["id"]);
-
-=head1 RELATIONS
-
-=head2 cachegroup
-
-Type: belongs_to
-
-Related object: L<Schema::Result::Cachegroup>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "cachegroup",
-  "Schema::Result::Cachegroup",
-  { id => "cachegroup" },
-  { is_deferrable => 1, on_delete => "CASCADE", on_update => "RESTRICT" },
-);
-
-=head2 deliveryservice_servers
-
-Type: has_many
-
-Related object: L<Schema::Result::DeliveryserviceServer>
-
-=cut
-
-__PACKAGE__->has_many(
-  "deliveryservice_servers",
-  "Schema::Result::DeliveryserviceServer",
-  { "foreign.server" => "self.id" },
-  { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 hwinfos
-
-Type: has_many
-
-Related object: L<Schema::Result::Hwinfo>
-
-=cut
-
-__PACKAGE__->has_many(
-  "hwinfos",
-  "Schema::Result::Hwinfo",
-  { "foreign.serverid" => "self.id" },
-  { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 phys_location
-
-Type: belongs_to
-
-Related object: L<Schema::Result::PhysLocation>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "phys_location",
-  "Schema::Result::PhysLocation",
-  { id => "phys_location" },
-  { is_deferrable => 1, on_delete => "NO ACTION", on_update => "NO ACTION" },
-);
-
-=head2 profile
-
-Type: belongs_to
-
-Related object: L<Schema::Result::Profile>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "profile",
-  "Schema::Result::Profile",
-  { id => "profile" },
-  { is_deferrable => 1, on_delete => "NO ACTION", on_update => "NO ACTION" },
-);
-
-=head2 servercheck
-
-Type: might_have
-
-Related object: L<Schema::Result::Servercheck>
-
-=cut
-
-__PACKAGE__->might_have(
-  "servercheck",
-  "Schema::Result::Servercheck",
-  { "foreign.server" => "self.id" },
-  { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 status
-
-Type: belongs_to
-
-Related object: L<Schema::Result::Status>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "status",
-  "Schema::Result::Status",
-  { id => "status" },
-  { is_deferrable => 1, on_delete => "NO ACTION", on_update => "NO ACTION" },
-);
-
-=head2 type
-
-Type: belongs_to
-
-Related object: L<Schema::Result::Type>
-
-=cut
-
-__PACKAGE__->belongs_to(
-  "type",
-  "Schema::Result::Type",
-  { id => "type" },
-  { is_deferrable => 1, on_delete => "NO ACTION", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07043 @ 2015-05-21 13:27:11
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:mecAHLqlmqBRoRpMOHaiOQ
-
-
-# You can replace this text with custom code or comments, and it will be preserved on regeneration
-#
-#
-# Licensed 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.
-#
-#
-1;
-# End of lines loaded from '/Users/drichard/projects/github.com/traffic_control/traffic_ops/app/lib/Schema/Result/Server.pm'
-
-
-# You can replace this text with custom code or comments, and it will be preserved on regeneration
-#
-#
-# Licensed 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.
-#
-#
 1;

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/b3e3344f/traffic_ops/app/lib/Schema/Result/SteeringView.pm
----------------------------------------------------------------------
diff --git a/traffic_ops/app/lib/Schema/Result/SteeringView.pm b/traffic_ops/app/lib/Schema/Result/SteeringView.pm
index 6a8311b..29612da 100644
--- a/traffic_ops/app/lib/Schema/Result/SteeringView.pm
+++ b/traffic_ops/app/lib/Schema/Result/SteeringView.pm
@@ -1,25 +1,3 @@
-package SteeringView;
-
-# 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.
-
-use strict;
-use warnings FATAL => 'all';
-
 package Schema::Result::SteeringView;
 
 # Licensed to the Apache Software Foundation (ASF) under one


[3/5] incubator-trafficcontrol git commit: This closes #207

Posted by ne...@apache.org.
This closes #207


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/3aa3c89b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/3aa3c89b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/3aa3c89b

Branch: refs/heads/master
Commit: 3aa3c89bf76e326dd53e9a241efd6a729fb6f782
Parents: 963e4dd
Author: David Neuman <da...@gmail.com>
Authored: Mon Jan 23 10:26:08 2017 -0700
Committer: David Neuman <da...@gmail.com>
Committed: Mon Jan 23 10:26:08 2017 -0700

----------------------------------------------------------------------

----------------------------------------------------------------------



[5/5] incubator-trafficcontrol git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol

Posted by ne...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/7591165d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/7591165d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/7591165d

Branch: refs/heads/master
Commit: 7591165d825612fafad365422d6d34265fb87a74
Parents: b3e3344 bf0b088
Author: David Neuman <da...@gmail.com>
Authored: Mon Jan 23 10:27:19 2017 -0700
Committer: David Neuman <da...@gmail.com>
Committed: Mon Jan 23 10:27:19 2017 -0700

----------------------------------------------------------------------

----------------------------------------------------------------------