http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go
new file mode 100644
index 0000000..03f74f7
--- /dev/null
+++ 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_bufferedwriter_test.go
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "testing"
+)
+
+func TestChunkWriteOnFilling(t *testing.T) {
+       writer, _ := newBytesVerifier(t)
+       bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
+
+       if err != nil {
+               t.Fatalf("Unexpected buffered writer creation error: %s", 
err.Error())
+       }
+
+       bytes := make([]byte, 1000)
+
+       bufferedWriter.Write(bytes)
+       writer.ExpectBytes(bytes)
+       bufferedWriter.Write(bytes)
+}
+
+func TestFlushByTimePeriod(t *testing.T) {
+       writer, _ := newBytesVerifier(t)
+       bufferedWriter, err := NewBufferedWriter(writer, 1024, 10)
+
+       if err != nil {
+               t.Fatalf("Unexpected buffered writer creation error: %s", 
err.Error())
+       }
+
+       bytes := []byte("Hello")
+
+       for i := 0; i < 2; i++ {
+               writer.ExpectBytes(bytes)
+               bufferedWriter.Write(bytes)
+       }
+}
+
+func TestBigMessageMustPassMemoryBuffer(t *testing.T) {
+       writer, _ := newBytesVerifier(t)
+       bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
+
+       if err != nil {
+               t.Fatalf("Unexpected buffered writer creation error: %s", 
err.Error())
+       }
+
+       bytes := make([]byte, 5000)
+
+       for i := 0; i < len(bytes); i++ {
+               bytes[i] = uint8(i % 255)
+       }
+
+       writer.ExpectBytes(bytes)
+       bufferedWriter.Write(bytes)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_connwriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git a/traffic_stats/vendor/github.com/cihub/seelog/writers_connwriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_connwriter.go
new file mode 100644
index 0000000..d199894
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_connwriter.go
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "crypto/tls"
+       "fmt"
+       "io"
+       "net"
+)
+
+// connWriter is used to write to a stream-oriented network connection.
+type connWriter struct {
+       innerWriter    io.WriteCloser
+       reconnectOnMsg bool
+       reconnect      bool
+       net            string
+       addr           string
+       useTLS         bool
+       configTLS      *tls.Config
+}
+
+// Creates writer to the address addr on the network netName.
+// Connection will be opened on each write if reconnectOnMsg = true
+func NewConnWriter(netName string, addr string, reconnectOnMsg bool) 
*connWriter {
+       newWriter := new(connWriter)
+
+       newWriter.net = netName
+       newWriter.addr = addr
+       newWriter.reconnectOnMsg = reconnectOnMsg
+
+       return newWriter
+}
+
+// Creates a writer that uses SSL/TLS
+func newTLSWriter(netName string, addr string, reconnectOnMsg bool, config 
*tls.Config) *connWriter {
+       newWriter := new(connWriter)
+
+       newWriter.net = netName
+       newWriter.addr = addr
+       newWriter.reconnectOnMsg = reconnectOnMsg
+       newWriter.useTLS = true
+       newWriter.configTLS = config
+
+       return newWriter
+}
+
+func (connWriter *connWriter) Close() error {
+       if connWriter.innerWriter == nil {
+               return nil
+       }
+
+       return connWriter.innerWriter.Close()
+}
+
+func (connWriter *connWriter) Write(bytes []byte) (n int, err error) {
+       if connWriter.neededConnectOnMsg() {
+               err = connWriter.connect()
+               if err != nil {
+                       return 0, err
+               }
+       }
+
+       if connWriter.reconnectOnMsg {
+               defer connWriter.innerWriter.Close()
+       }
+
+       n, err = connWriter.innerWriter.Write(bytes)
+       if err != nil {
+               connWriter.reconnect = true
+       }
+
+       return
+}
+
+func (connWriter *connWriter) String() string {
+       return fmt.Sprintf("Conn writer: [%s, %s, %v]", connWriter.net, 
connWriter.addr, connWriter.reconnectOnMsg)
+}
+
+func (connWriter *connWriter) connect() error {
+       if connWriter.innerWriter != nil {
+               connWriter.innerWriter.Close()
+               connWriter.innerWriter = nil
+       }
+
+       if connWriter.useTLS {
+               conn, err := tls.Dial(connWriter.net, connWriter.addr, 
connWriter.configTLS)
+               if err != nil {
+                       return err
+               }
+               connWriter.innerWriter = conn
+
+               return nil
+       }
+
+       conn, err := net.Dial(connWriter.net, connWriter.addr)
+       if err != nil {
+               return err
+       }
+
+       tcpConn, ok := conn.(*net.TCPConn)
+       if ok {
+               tcpConn.SetKeepAlive(true)
+       }
+
+       connWriter.innerWriter = conn
+
+       return nil
+}
+
+func (connWriter *connWriter) neededConnectOnMsg() bool {
+       if connWriter.reconnect {
+               connWriter.reconnect = false
+               return true
+       }
+
+       if connWriter.innerWriter == nil {
+               return true
+       }
+
+       return connWriter.reconnectOnMsg
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_consolewriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_consolewriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_consolewriter.go
new file mode 100644
index 0000000..3eb79af
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_consolewriter.go
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import "fmt"
+
+// consoleWriter is used to write to console
+type consoleWriter struct {
+}
+
+// Creates a new console writer. Returns error, if the console writer couldn't 
be created.
+func NewConsoleWriter() (writer *consoleWriter, err error) {
+       newWriter := new(consoleWriter)
+
+       return newWriter, nil
+}
+
+// Create folder and file on WriteLog/Write first call
+func (console *consoleWriter) Write(bytes []byte) (int, error) {
+       return fmt.Print(string(bytes))
+}
+
+func (console *consoleWriter) String() string {
+       return "Console writer"
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git a/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter.go
new file mode 100644
index 0000000..8d3ae27
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter.go
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+)
+
+// fileWriter is used to write to a file.
+type fileWriter struct {
+       innerWriter io.WriteCloser
+       fileName    string
+}
+
+// Creates a new file and a corresponding writer. Returns error, if the file 
couldn't be created.
+func NewFileWriter(fileName string) (writer *fileWriter, err error) {
+       newWriter := new(fileWriter)
+       newWriter.fileName = fileName
+
+       return newWriter, nil
+}
+
+func (fw *fileWriter) Close() error {
+       if fw.innerWriter != nil {
+               err := fw.innerWriter.Close()
+               if err != nil {
+                       return err
+               }
+               fw.innerWriter = nil
+       }
+       return nil
+}
+
+// Create folder and file on WriteLog/Write first call
+func (fw *fileWriter) Write(bytes []byte) (n int, err error) {
+       if fw.innerWriter == nil {
+               if err := fw.createFile(); err != nil {
+                       return 0, err
+               }
+       }
+       return fw.innerWriter.Write(bytes)
+}
+
+func (fw *fileWriter) createFile() error {
+       folder, _ := filepath.Split(fw.fileName)
+       var err error
+
+       if 0 != len(folder) {
+               err = os.MkdirAll(folder, defaultDirectoryPermissions)
+               if err != nil {
+                       return err
+               }
+       }
+
+       // If exists
+       fw.innerWriter, err = os.OpenFile(fw.fileName, 
os.O_WRONLY|os.O_APPEND|os.O_CREATE, defaultFilePermissions)
+
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (fw *fileWriter) String() string {
+       return fmt.Sprintf("File writer: %s", fw.fileName)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter_test.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter_test.go
new file mode 100644
index 0000000..f723912
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_filewriter_test.go
@@ -0,0 +1,257 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+       "strings"
+       "testing"
+)
+
+const (
+       messageLen = 10
+)
+
+var bytesFileTest = []byte(strings.Repeat("A", messageLen))
+
+func TestSimpleFileWriter(t *testing.T) {
+       t.Logf("Starting file writer tests")
+       NewFileWriterTester(simplefileWriterTests, simplefileWriterGetter, 
t).test()
+}
+
+//===============================================================
+
+func simplefileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, 
error) {
+       return NewFileWriter(testCase.fileName)
+}
+
+//===============================================================
+type fileWriterTestCase struct {
+       files           []string
+       fileName        string
+       rollingType     rollingType
+       fileSize        int64
+       maxRolls        int
+       datePattern     string
+       writeCount      int
+       resFiles        []string
+       nameMode        rollingNameMode
+       archiveType     rollingArchiveType
+       archiveExploded bool
+       archivePath     string
+}
+
+func createSimplefileWriterTestCase(fileName string, writeCount int) 
*fileWriterTestCase {
+       return &fileWriterTestCase{[]string{}, fileName, rollingTypeSize, 0, 0, 
"", writeCount, []string{fileName}, 0, rollingArchiveNone, false, ""}
+}
+
+var simplefileWriterTests = []*fileWriterTestCase{
+       createSimplefileWriterTestCase("log.testlog", 1),
+       createSimplefileWriterTestCase("log.testlog", 50),
+       createSimplefileWriterTestCase(filepath.Join("dir", "log.testlog"), 50),
+}
+
+//===============================================================
+
+type fileWriterTester struct {
+       testCases    []*fileWriterTestCase
+       writerGetter func(*fileWriterTestCase) (io.WriteCloser, error)
+       t            *testing.T
+}
+
+func NewFileWriterTester(
+       testCases []*fileWriterTestCase,
+       writerGetter func(*fileWriterTestCase) (io.WriteCloser, error),
+       t *testing.T) *fileWriterTester {
+
+       return &fileWriterTester{testCases, writerGetter, t}
+}
+
+func isWriterTestFile(fn string) bool {
+       return strings.Contains(fn, ".testlog") || strings.Contains(fn, ".zip") 
|| strings.Contains(fn, ".gz")
+}
+
+func cleanupWriterTest(t *testing.T) {
+       toDel, err := getDirFilePaths(".", isWriterTestFile, true)
+       if nil != err {
+               t.Fatal("Cannot list files in test directory!")
+       }
+
+       for _, p := range toDel {
+               if err = tryRemoveFile(p); nil != err {
+                       t.Errorf("cannot remove file %s in test directory: %s", 
p, err.Error())
+               }
+       }
+
+       if err = os.RemoveAll("dir"); nil != err {
+               t.Errorf("cannot remove temp test directory: %s", err.Error())
+       }
+}
+
+func getWriterTestResultFiles() ([]string, error) {
+       var p []string
+
+       visit := func(path string, f os.FileInfo, err error) error {
+               if !f.IsDir() && isWriterTestFile(path) {
+                       abs, err := filepath.Abs(path)
+                       if err != nil {
+                               return fmt.Errorf("filepath.Abs failed for %s", 
path)
+                       }
+
+                       p = append(p, abs)
+               }
+
+               return nil
+       }
+
+       err := filepath.Walk(".", visit)
+       if nil != err {
+               return nil, err
+       }
+
+       return p, nil
+}
+
+func (tester *fileWriterTester) testCase(testCase *fileWriterTestCase, testNum 
int) {
+       defer cleanupWriterTest(tester.t)
+
+       tester.t.Logf("Start test  [%v]\n", testNum)
+
+       for _, filePath := range testCase.files {
+               dir, _ := filepath.Split(filePath)
+
+               var err error
+
+               if 0 != len(dir) {
+                       err = os.MkdirAll(dir, defaultDirectoryPermissions)
+                       if err != nil {
+                               tester.t.Error(err)
+                               return
+                       }
+               }
+
+               fi, err := os.Create(filePath)
+               if err != nil {
+                       tester.t.Error(err)
+                       return
+               }
+
+               err = fi.Close()
+               if err != nil {
+                       tester.t.Error(err)
+                       return
+               }
+       }
+
+       fwc, err := tester.writerGetter(testCase)
+       if err != nil {
+               tester.t.Error(err)
+               return
+       }
+       defer fwc.Close()
+
+       tester.performWrite(fwc, testCase.writeCount)
+
+       files, err := getWriterTestResultFiles()
+       if err != nil {
+               tester.t.Error(err)
+               return
+       }
+
+       tester.checkRequiredFilesExist(testCase, files)
+       tester.checkJustRequiredFilesExist(testCase, files)
+
+}
+
+func (tester *fileWriterTester) test() {
+       for i, tc := range tester.testCases {
+               cleanupWriterTest(tester.t)
+               tester.testCase(tc, i)
+       }
+}
+
+func (tester *fileWriterTester) performWrite(fileWriter io.Writer, count int) {
+       for i := 0; i < count; i++ {
+               _, err := fileWriter.Write(bytesFileTest)
+
+               if err != nil {
+                       tester.t.Error(err)
+                       return
+               }
+       }
+}
+
+func (tester *fileWriterTester) checkRequiredFilesExist(testCase 
*fileWriterTestCase, files []string) {
+       var found bool
+       for _, expected := range testCase.resFiles {
+               found = false
+               exAbs, err := filepath.Abs(expected)
+               if err != nil {
+                       tester.t.Errorf("filepath.Abs failed for %s", expected)
+                       continue
+               }
+
+               for _, f := range files {
+                       if af, e := filepath.Abs(f); e == nil {
+                               tester.t.Log(af)
+                               if exAbs == af {
+                                       found = true
+                                       break
+                               }
+                       } else {
+                               tester.t.Errorf("filepath.Abs failed for %s", f)
+                       }
+               }
+
+               if !found {
+                       tester.t.Errorf("expected file: %s doesn't exist. Got 
%v\n", exAbs, files)
+               }
+       }
+}
+
+func (tester *fileWriterTester) checkJustRequiredFilesExist(testCase 
*fileWriterTestCase, files []string) {
+       for _, f := range files {
+               found := false
+               for _, expected := range testCase.resFiles {
+
+                       exAbs, err := filepath.Abs(expected)
+                       if err != nil {
+                               tester.t.Errorf("filepath.Abs failed for %s", 
expected)
+                       } else {
+                               if exAbs == f {
+                                       found = true
+                                       break
+                               }
+                       }
+               }
+
+               if !found {
+                       tester.t.Errorf("unexpected file: %v", f)
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter.go
new file mode 100644
index 0000000..bf44a41
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter.go
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "errors"
+       "fmt"
+       "io"
+)
+
+type formattedWriter struct {
+       writer    io.Writer
+       formatter *formatter
+}
+
+func NewFormattedWriter(writer io.Writer, formatter *formatter) 
(*formattedWriter, error) {
+       if formatter == nil {
+               return nil, errors.New("formatter can not be nil")
+       }
+
+       return &formattedWriter{writer, formatter}, nil
+}
+
+func (formattedWriter *formattedWriter) Write(message string, level LogLevel, 
context LogContextInterface) error {
+       str := formattedWriter.formatter.Format(message, level, context)
+       _, err := formattedWriter.writer.Write([]byte(str))
+       return err
+}
+
+func (formattedWriter *formattedWriter) String() string {
+       return fmt.Sprintf("writer: %s, format: %s", formattedWriter.writer, 
formattedWriter.formatter)
+}
+
+func (formattedWriter *formattedWriter) Writer() io.Writer {
+       return formattedWriter.writer
+}
+
+func (formattedWriter *formattedWriter) Format() *formatter {
+       return formattedWriter.formatter
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go
new file mode 100644
index 0000000..351ac4e
--- /dev/null
+++ 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_formattedwriter_test.go
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "testing"
+)
+
+func TestformattedWriter(t *testing.T) {
+       formatStr := "%Level %LEVEL %Msg"
+       message := "message"
+       var logLevel = LogLevel(TraceLvl)
+
+       bytesVerifier, err := newBytesVerifier(t)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       formatter, err := NewFormatter(formatStr)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       writer, err := NewFormattedWriter(bytesVerifier, formatter)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       context, err := currentContext(nil)
+       if err != nil {
+               t.Error(err)
+               return
+       }
+
+       logMessage := formatter.Format(message, logLevel, context)
+
+       bytesVerifier.ExpectBytes([]byte(logMessage))
+       writer.Write(message, logLevel, context)
+       bytesVerifier.MustNotExpect()
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter.go
new file mode 100644
index 0000000..d3903bb
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter.go
@@ -0,0 +1,770 @@
+// Copyright (c) 2013 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "fmt"
+       "io"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "sort"
+       "strconv"
+       "strings"
+       "sync"
+       "time"
+
+       "github.com/cihub/seelog/archive"
+       "github.com/cihub/seelog/archive/gzip"
+       "github.com/cihub/seelog/archive/tar"
+       "github.com/cihub/seelog/archive/zip"
+)
+
+// Common constants
+const (
+       rollingLogHistoryDelimiter = "."
+)
+
+// Types of the rolling writer: roll by date, by time, etc.
+type rollingType uint8
+
+const (
+       rollingTypeSize = iota
+       rollingTypeTime
+)
+
+// Types of the rolled file naming mode: prefix, postfix, etc.
+type rollingNameMode uint8
+
+const (
+       rollingNameModePostfix = iota
+       rollingNameModePrefix
+)
+
+var rollingNameModesStringRepresentation = map[rollingNameMode]string{
+       rollingNameModePostfix: "postfix",
+       rollingNameModePrefix:  "prefix",
+}
+
+func rollingNameModeFromString(rollingNameStr string) (rollingNameMode, bool) {
+       for tp, tpStr := range rollingNameModesStringRepresentation {
+               if tpStr == rollingNameStr {
+                       return tp, true
+               }
+       }
+
+       return 0, false
+}
+
+var rollingTypesStringRepresentation = map[rollingType]string{
+       rollingTypeSize: "size",
+       rollingTypeTime: "date",
+}
+
+func rollingTypeFromString(rollingTypeStr string) (rollingType, bool) {
+       for tp, tpStr := range rollingTypesStringRepresentation {
+               if tpStr == rollingTypeStr {
+                       return tp, true
+               }
+       }
+
+       return 0, false
+}
+
+// Old logs archivation type.
+type rollingArchiveType uint8
+
+const (
+       rollingArchiveNone = iota
+       rollingArchiveZip
+       rollingArchiveGzip
+)
+
+var rollingArchiveTypesStringRepresentation = map[rollingArchiveType]string{
+       rollingArchiveNone: "none",
+       rollingArchiveZip:  "zip",
+       rollingArchiveGzip: "gzip",
+}
+
+type archiver func(f *os.File, exploded bool) archive.WriteCloser
+
+type unarchiver func(f *os.File) (archive.ReadCloser, error)
+
+type compressionType struct {
+       extension             string
+       handleMultipleEntries bool
+       archiver              archiver
+       unarchiver            unarchiver
+}
+
+var compressionTypes = map[rollingArchiveType]compressionType{
+       rollingArchiveZip: {
+               extension:             ".zip",
+               handleMultipleEntries: true,
+               archiver: func(f *os.File, _ bool) archive.WriteCloser {
+                       return zip.NewWriter(f)
+               },
+               unarchiver: func(f *os.File) (archive.ReadCloser, error) {
+                       fi, err := f.Stat()
+                       if err != nil {
+                               return nil, err
+                       }
+                       r, err := zip.NewReader(f, fi.Size())
+                       if err != nil {
+                               return nil, err
+                       }
+                       return archive.NopCloser(r), nil
+               },
+       },
+       rollingArchiveGzip: {
+               extension:             ".gz",
+               handleMultipleEntries: false,
+               archiver: func(f *os.File, exploded bool) archive.WriteCloser {
+                       gw := gzip.NewWriter(f)
+                       if exploded {
+                               return gw
+                       }
+                       return tar.NewWriteMultiCloser(gw, gw)
+               },
+               unarchiver: func(f *os.File) (archive.ReadCloser, error) {
+                       gr, err := gzip.NewReader(f, f.Name())
+                       if err != nil {
+                               return nil, err
+                       }
+
+                       // Determine if the gzip is a tar
+                       tr := tar.NewReader(gr)
+                       _, err = tr.Next()
+                       isTar := err == nil
+
+                       // Reset to beginning of file
+                       if _, err := f.Seek(0, os.SEEK_SET); err != nil {
+                               return nil, err
+                       }
+                       gr.Reset(f)
+
+                       if isTar {
+                               return archive.NopCloser(tar.NewReader(gr)), nil
+                       }
+                       return gr, nil
+               },
+       },
+}
+
+func (compressionType *compressionType) rollingArchiveTypeName(name string, 
exploded bool) string {
+       if !compressionType.handleMultipleEntries && !exploded {
+               return name + ".tar" + compressionType.extension
+       } else {
+               return name + compressionType.extension
+       }
+
+}
+
+func rollingArchiveTypeFromString(rollingArchiveTypeStr string) 
(rollingArchiveType, bool) {
+       for tp, tpStr := range rollingArchiveTypesStringRepresentation {
+               if tpStr == rollingArchiveTypeStr {
+                       return tp, true
+               }
+       }
+
+       return 0, false
+}
+
+// Default names for different archive types
+var rollingArchiveDefaultExplodedName = "old"
+
+func rollingArchiveTypeDefaultName(archiveType rollingArchiveType, exploded 
bool) (string, error) {
+       compressionType, ok := compressionTypes[archiveType]
+       if !ok {
+               return "", fmt.Errorf("cannot get default filename for archive 
type = %v", archiveType)
+       }
+       return compressionType.rollingArchiveTypeName("log", exploded), nil
+}
+
+// rollerVirtual is an interface that represents all virtual funcs that are
+// called in different rolling writer subtypes.
+type rollerVirtual interface {
+       needsToRoll() bool                                  // Returns true if 
needs to switch to another file.
+       isFileRollNameValid(rname string) bool              // Returns true if 
logger roll file name (postfix/prefix/etc.) is ok.
+       sortFileRollNamesAsc(fs []string) ([]string, error) // Sorts logger 
roll file names in ascending order of their creation by logger.
+
+       // getNewHistoryRollFileName is called whenever we are about to roll the
+       // current log file. It returns the name the current log file should be
+       // rolled to.
+       getNewHistoryRollFileName(otherHistoryFiles []string) string
+
+       getCurrentFileName() string
+}
+
+// rollingFileWriter writes received messages to a file, until time interval 
passes
+// or file exceeds a specified limit. After that the current log file is 
renamed
+// and writer starts to log into a new file. You can set a limit for such 
renamed
+// files count, if you want, and then the rolling writer would delete older 
ones when
+// the files count exceed the specified limit.
+type rollingFileWriter struct {
+       fileName        string // log file name
+       currentDirPath  string
+       currentFile     *os.File
+       currentName     string
+       currentFileSize int64
+       rollingType     rollingType // Rolling mode (Files roll by 
size/date/...)
+       archiveType     rollingArchiveType
+       archivePath     string
+       archiveExploded bool
+       fullName        bool
+       maxRolls        int
+       nameMode        rollingNameMode
+       self            rollerVirtual // Used for virtual calls
+       rollLock        sync.Mutex
+}
+
+func newRollingFileWriter(fpath string, rtype rollingType, atype 
rollingArchiveType, apath string, maxr int, namemode rollingNameMode,
+       archiveExploded bool, fullName bool) (*rollingFileWriter, error) {
+       rw := new(rollingFileWriter)
+       rw.currentDirPath, rw.fileName = filepath.Split(fpath)
+       if len(rw.currentDirPath) == 0 {
+               rw.currentDirPath = "."
+       }
+
+       rw.rollingType = rtype
+       rw.archiveType = atype
+       rw.archivePath = apath
+       rw.nameMode = namemode
+       rw.maxRolls = maxr
+       rw.archiveExploded = archiveExploded
+       rw.fullName = fullName
+       return rw, nil
+}
+
+func (rw *rollingFileWriter) hasRollName(file string) bool {
+       switch rw.nameMode {
+       case rollingNameModePostfix:
+               rname := rw.fileName + rollingLogHistoryDelimiter
+               return strings.HasPrefix(file, rname)
+       case rollingNameModePrefix:
+               rname := rollingLogHistoryDelimiter + rw.fileName
+               return strings.HasSuffix(file, rname)
+       }
+       return false
+}
+
+func (rw *rollingFileWriter) createFullFileName(originalName, rollname string) 
string {
+       switch rw.nameMode {
+       case rollingNameModePostfix:
+               return originalName + rollingLogHistoryDelimiter + rollname
+       case rollingNameModePrefix:
+               return rollname + rollingLogHistoryDelimiter + originalName
+       }
+       return ""
+}
+
+func (rw *rollingFileWriter) getSortedLogHistory() ([]string, error) {
+       files, err := getDirFilePaths(rw.currentDirPath, nil, true)
+       if err != nil {
+               return nil, err
+       }
+       var validRollNames []string
+       for _, file := range files {
+               if rw.hasRollName(file) {
+                       rname := rw.getFileRollName(file)
+                       if rw.self.isFileRollNameValid(rname) {
+                               validRollNames = append(validRollNames, rname)
+                       }
+               }
+       }
+       sortedTails, err := rw.self.sortFileRollNamesAsc(validRollNames)
+       if err != nil {
+               return nil, err
+       }
+       validSortedFiles := make([]string, len(sortedTails))
+       for i, v := range sortedTails {
+               validSortedFiles[i] = rw.createFullFileName(rw.fileName, v)
+       }
+       return validSortedFiles, nil
+}
+
+func (rw *rollingFileWriter) createFileAndFolderIfNeeded(first bool) error {
+       var err error
+
+       if len(rw.currentDirPath) != 0 {
+               err = os.MkdirAll(rw.currentDirPath, 
defaultDirectoryPermissions)
+
+               if err != nil {
+                       return err
+               }
+       }
+       rw.currentName = rw.self.getCurrentFileName()
+       filePath := filepath.Join(rw.currentDirPath, rw.currentName)
+
+       // If exists
+       stat, err := os.Lstat(filePath)
+       if err == nil {
+               rw.currentFile, err = os.OpenFile(filePath, 
os.O_WRONLY|os.O_APPEND, defaultFilePermissions)
+               if err != nil {
+                       return err
+               }
+
+               stat, err = os.Lstat(filePath)
+               if err != nil {
+                       return err
+               }
+
+               rw.currentFileSize = stat.Size()
+       } else {
+               rw.currentFile, err = os.Create(filePath)
+               rw.currentFileSize = 0
+       }
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func (rw *rollingFileWriter) archiveExplodedLogs(logFilename string, 
compressionType compressionType) (err error) {
+       closeWithError := func(c io.Closer) {
+               if cerr := c.Close(); cerr != nil && err == nil {
+                       err = cerr
+               }
+       }
+
+       rollPath := filepath.Join(rw.currentDirPath, logFilename)
+       src, err := os.Open(rollPath)
+       if err != nil {
+               return err
+       }
+       defer src.Close() // Read-only
+
+       // Buffer to a temporary file on the same partition
+       // Note: archivePath is a path to a directory when handling exploded 
logs
+       dst, err := rw.tempArchiveFile(rw.archivePath)
+       if err != nil {
+               return err
+       }
+       defer func() {
+               closeWithError(dst)
+               if err != nil {
+                       os.Remove(dst.Name()) // Can't do anything when we fail 
to remove temp file
+                       return
+               }
+
+               // Finalize archive by swapping the buffered archive into place
+               err = os.Rename(dst.Name(), filepath.Join(rw.archivePath,
+                       compressionType.rollingArchiveTypeName(logFilename, 
true)))
+       }()
+
+       // archive entry
+       w := compressionType.archiver(dst, true)
+       defer closeWithError(w)
+       fi, err := src.Stat()
+       if err != nil {
+               return err
+       }
+       if err := w.NextFile(logFilename, fi); err != nil {
+               return err
+       }
+       _, err = io.Copy(w, src)
+       return err
+}
+
+func (rw *rollingFileWriter) archiveUnexplodedLogs(compressionType 
compressionType, rollsToDelete int, history []string) (err error) {
+       closeWithError := func(c io.Closer) {
+               if cerr := c.Close(); cerr != nil && err == nil {
+                       err = cerr
+               }
+       }
+
+       // Buffer to a temporary file on the same partition
+       // Note: archivePath is a path to a file when handling unexploded logs
+       dst, err := rw.tempArchiveFile(filepath.Dir(rw.archivePath))
+       if err != nil {
+               return err
+       }
+       defer func() {
+               closeWithError(dst)
+               if err != nil {
+                       os.Remove(dst.Name()) // Can't do anything when we fail 
to remove temp file
+                       return
+               }
+
+               // Finalize archive by moving the buffered archive into place
+               err = os.Rename(dst.Name(), rw.archivePath)
+       }()
+
+       w := compressionType.archiver(dst, false)
+       defer closeWithError(w)
+
+       src, err := os.Open(rw.archivePath)
+       switch {
+       // Archive exists
+       case err == nil:
+               defer src.Close() // Read-only
+
+               r, err := compressionType.unarchiver(src)
+               if err != nil {
+                       return err
+               }
+               defer r.Close() // Read-only
+
+               if err := archive.Copy(w, r); err != nil {
+                       return err
+               }
+
+       // Failed to stat
+       case !os.IsNotExist(err):
+               return err
+       }
+
+       // Add new files to the archive
+       for i := 0; i < rollsToDelete; i++ {
+               rollPath := filepath.Join(rw.currentDirPath, history[i])
+               src, err := os.Open(rollPath)
+               if err != nil {
+                       return err
+               }
+               defer src.Close() // Read-only
+               fi, err := src.Stat()
+               if err != nil {
+                       return err
+               }
+               if err := w.NextFile(src.Name(), fi); err != nil {
+                       return err
+               }
+               if _, err := io.Copy(w, src); err != nil {
+                       return err
+               }
+       }
+       return nil
+}
+
+func (rw *rollingFileWriter) deleteOldRolls(history []string) error {
+       if rw.maxRolls <= 0 {
+               return nil
+       }
+
+       rollsToDelete := len(history) - rw.maxRolls
+       if rollsToDelete <= 0 {
+               return nil
+       }
+
+       if rw.archiveType != rollingArchiveNone {
+               if rw.archiveExploded {
+                       os.MkdirAll(rw.archivePath, defaultDirectoryPermissions)
+
+                       // Archive logs
+                       for i := 0; i < rollsToDelete; i++ {
+                               rw.archiveExplodedLogs(history[i], 
compressionTypes[rw.archiveType])
+                       }
+               } else {
+                       os.MkdirAll(filepath.Dir(rw.archivePath), 
defaultDirectoryPermissions)
+
+                       
rw.archiveUnexplodedLogs(compressionTypes[rw.archiveType], rollsToDelete, 
history)
+               }
+       }
+
+       var err error
+       // In all cases (archive files or not) the files should be deleted.
+       for i := 0; i < rollsToDelete; i++ {
+               // Try best to delete files without breaking the loop.
+               if err = tryRemoveFile(filepath.Join(rw.currentDirPath, 
history[i])); err != nil {
+                       reportInternalError(err)
+               }
+       }
+
+       return nil
+}
+
+func (rw *rollingFileWriter) getFileRollName(fileName string) string {
+       switch rw.nameMode {
+       case rollingNameModePostfix:
+               return fileName[len(rw.fileName+rollingLogHistoryDelimiter):]
+       case rollingNameModePrefix:
+               return 
fileName[:len(fileName)-len(rw.fileName+rollingLogHistoryDelimiter)]
+       }
+       return ""
+}
+
+func (rw *rollingFileWriter) roll() error {
+       // First, close current file.
+       err := rw.currentFile.Close()
+       if err != nil {
+               return err
+       }
+       rw.currentFile = nil
+
+       // Current history of all previous log files.
+       // For file roller it may be like this:
+       //     * ...
+       //     * file.log.4
+       //     * file.log.5
+       //     * file.log.6
+       //
+       // For date roller it may look like this:
+       //     * ...
+       //     * file.log.11.Aug.13
+       //     * file.log.15.Aug.13
+       //     * file.log.16.Aug.13
+       // Sorted log history does NOT include current file.
+       history, err := rw.getSortedLogHistory()
+       if err != nil {
+               return err
+       }
+       // Renames current file to create a new roll history entry
+       // For file roller it may be like this:
+       //     * ...
+       //     * file.log.4
+       //     * file.log.5
+       //     * file.log.6
+       //     n file.log.7  <---- RENAMED (from file.log)
+       newHistoryName := rw.createFullFileName(rw.fileName,
+               rw.self.getNewHistoryRollFileName(history))
+
+       err = os.Rename(filepath.Join(rw.currentDirPath, rw.currentName), 
filepath.Join(rw.currentDirPath, newHistoryName))
+       if err != nil {
+               return err
+       }
+
+       // Finally, add the newly added history file to the history archive
+       // and, if after that the archive exceeds the allowed max limit, older 
rolls
+       // must the removed/archived.
+       history = append(history, newHistoryName)
+       if len(history) > rw.maxRolls {
+               err = rw.deleteOldRolls(history)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (rw *rollingFileWriter) Write(bytes []byte) (n int, err error) {
+       rw.rollLock.Lock()
+       defer rw.rollLock.Unlock()
+
+       if rw.self.needsToRoll() {
+               if err := rw.roll(); err != nil {
+                       return 0, err
+               }
+       }
+
+       if rw.currentFile == nil {
+               err := rw.createFileAndFolderIfNeeded(true)
+               if err != nil {
+                       return 0, err
+               }
+       }
+
+       n, err = rw.currentFile.Write(bytes)
+       rw.currentFileSize += int64(n)
+       return n, err
+}
+
+func (rw *rollingFileWriter) Close() error {
+       if rw.currentFile != nil {
+               e := rw.currentFile.Close()
+               if e != nil {
+                       return e
+               }
+               rw.currentFile = nil
+       }
+       return nil
+}
+
+func (rw *rollingFileWriter) tempArchiveFile(archiveDir string) (*os.File, 
error) {
+       tmp := filepath.Join(archiveDir, ".seelog_tmp")
+       if err := os.MkdirAll(tmp, defaultDirectoryPermissions); err != nil {
+               return nil, err
+       }
+       return ioutil.TempFile(tmp, "archived_logs")
+}
+
+// 
=============================================================================================
+//      Different types of rolling writers
+// 
=============================================================================================
+
+// --------------------------------------------------
+//      Rolling writer by SIZE
+// --------------------------------------------------
+
+// rollingFileWriterSize performs roll when file exceeds a specified limit.
+type rollingFileWriterSize struct {
+       *rollingFileWriter
+       maxFileSize int64
+}
+
+func NewRollingFileWriterSize(fpath string, atype rollingArchiveType, apath 
string, maxSize int64, maxRolls int, namemode rollingNameMode, archiveExploded 
bool) (*rollingFileWriterSize, error) {
+       rw, err := newRollingFileWriter(fpath, rollingTypeSize, atype, apath, 
maxRolls, namemode, archiveExploded, false)
+       if err != nil {
+               return nil, err
+       }
+       rws := &rollingFileWriterSize{rw, maxSize}
+       rws.self = rws
+       return rws, nil
+}
+
+func (rws *rollingFileWriterSize) needsToRoll() bool {
+       return rws.currentFileSize >= rws.maxFileSize
+}
+
+func (rws *rollingFileWriterSize) isFileRollNameValid(rname string) bool {
+       if len(rname) == 0 {
+               return false
+       }
+       _, err := strconv.Atoi(rname)
+       return err == nil
+}
+
+type rollSizeFileTailsSlice []string
+
+func (p rollSizeFileTailsSlice) Len() int {
+       return len(p)
+}
+func (p rollSizeFileTailsSlice) Less(i, j int) bool {
+       v1, _ := strconv.Atoi(p[i])
+       v2, _ := strconv.Atoi(p[j])
+       return v1 < v2
+}
+func (p rollSizeFileTailsSlice) Swap(i, j int) {
+       p[i], p[j] = p[j], p[i]
+}
+
+func (rws *rollingFileWriterSize) sortFileRollNamesAsc(fs []string) ([]string, 
error) {
+       ss := rollSizeFileTailsSlice(fs)
+       sort.Sort(ss)
+       return ss, nil
+}
+
+func (rws *rollingFileWriterSize) getNewHistoryRollFileName(otherLogFiles 
[]string) string {
+       v := 0
+       if len(otherLogFiles) != 0 {
+               latest := otherLogFiles[len(otherLogFiles)-1]
+               v, _ = strconv.Atoi(rws.getFileRollName(latest))
+       }
+       return fmt.Sprintf("%d", v+1)
+}
+
+func (rws *rollingFileWriterSize) getCurrentFileName() string {
+       return rws.fileName
+}
+
+func (rws *rollingFileWriterSize) String() string {
+       return fmt.Sprintf("Rolling file writer (By SIZE): filename: %s, 
archive: %s, archivefile: %s, maxFileSize: %v, maxRolls: %v",
+               rws.fileName,
+               rollingArchiveTypesStringRepresentation[rws.archiveType],
+               rws.archivePath,
+               rws.maxFileSize,
+               rws.maxRolls)
+}
+
+// --------------------------------------------------
+//      Rolling writer by TIME
+// --------------------------------------------------
+
+// rollingFileWriterTime performs roll when a specified time interval has 
passed.
+type rollingFileWriterTime struct {
+       *rollingFileWriter
+       timePattern         string
+       currentTimeFileName string
+}
+
+func NewRollingFileWriterTime(fpath string, atype rollingArchiveType, apath 
string, maxr int,
+       timePattern string, namemode rollingNameMode, archiveExploded bool, 
fullName bool) (*rollingFileWriterTime, error) {
+
+       rw, err := newRollingFileWriter(fpath, rollingTypeTime, atype, apath, 
maxr, namemode, archiveExploded, fullName)
+       if err != nil {
+               return nil, err
+       }
+       rws := &rollingFileWriterTime{rw, timePattern, ""}
+       rws.self = rws
+       return rws, nil
+}
+
+func (rwt *rollingFileWriterTime) needsToRoll() bool {
+       newName := time.Now().Format(rwt.timePattern)
+
+       if rwt.currentTimeFileName == "" {
+               // first run; capture the current name
+               rwt.currentTimeFileName = newName
+               return false
+       }
+
+       return newName != rwt.currentTimeFileName
+}
+
+func (rwt *rollingFileWriterTime) isFileRollNameValid(rname string) bool {
+       if len(rname) == 0 {
+               return false
+       }
+       _, err := time.ParseInLocation(rwt.timePattern, rname, time.Local)
+       return err == nil
+}
+
+type rollTimeFileTailsSlice struct {
+       data    []string
+       pattern string
+}
+
+func (p rollTimeFileTailsSlice) Len() int {
+       return len(p.data)
+}
+
+func (p rollTimeFileTailsSlice) Less(i, j int) bool {
+       t1, _ := time.ParseInLocation(p.pattern, p.data[i], time.Local)
+       t2, _ := time.ParseInLocation(p.pattern, p.data[j], time.Local)
+       return t1.Before(t2)
+}
+
+func (p rollTimeFileTailsSlice) Swap(i, j int) {
+       p.data[i], p.data[j] = p.data[j], p.data[i]
+}
+
+func (rwt *rollingFileWriterTime) sortFileRollNamesAsc(fs []string) ([]string, 
error) {
+       ss := rollTimeFileTailsSlice{data: fs, pattern: rwt.timePattern}
+       sort.Sort(ss)
+       return ss.data, nil
+}
+
+func (rwt *rollingFileWriterTime) getNewHistoryRollFileName(_ []string) string 
{
+       newFileName := rwt.currentTimeFileName
+       rwt.currentTimeFileName = time.Now().Format(rwt.timePattern)
+       return newFileName
+}
+
+func (rwt *rollingFileWriterTime) getCurrentFileName() string {
+       if rwt.fullName {
+               return rwt.createFullFileName(rwt.fileName, 
time.Now().Format(rwt.timePattern))
+       }
+       return rwt.fileName
+}
+
+func (rwt *rollingFileWriterTime) String() string {
+       return fmt.Sprintf("Rolling file writer (By TIME): filename: %s, 
archive: %s, archivefile: %s, pattern: %s, maxRolls: %v",
+               rwt.fileName,
+               rollingArchiveTypesStringRepresentation[rwt.archiveType],
+               rwt.archivePath,
+               rwt.timePattern,
+               rwt.maxRolls)
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git 
a/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
new file mode 100644
index 0000000..b23c959
--- /dev/null
+++ 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_rollingfilewriter_test.go
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "fmt"
+       "io"
+       "testing"
+)
+
+// fileWriterTestCase is declared in writers_filewriter_test.go
+
+func createRollingSizeFileWriterTestCase(
+       files []string,
+       fileName string,
+       fileSize int64,
+       maxRolls int,
+       writeCount int,
+       resFiles []string,
+       nameMode rollingNameMode,
+       archiveType rollingArchiveType,
+       archiveExploded bool,
+       archivePath string) *fileWriterTestCase {
+
+       return &fileWriterTestCase{files, fileName, rollingTypeSize, fileSize, 
maxRolls, "", writeCount, resFiles, nameMode, archiveType, archiveExploded, 
archivePath}
+}
+
+func createRollingDatefileWriterTestCase(
+       files []string,
+       fileName string,
+       datePattern string,
+       writeCount int,
+       resFiles []string,
+       nameMode rollingNameMode,
+       archiveType rollingArchiveType,
+       archiveExploded bool,
+       archivePath string) *fileWriterTestCase {
+
+       return &fileWriterTestCase{files, fileName, rollingTypeTime, 0, 0, 
datePattern, writeCount, resFiles, nameMode, archiveType, archiveExploded, 
archivePath}
+}
+
+func TestShouldArchiveWithTar(t *testing.T) {
+       compressionType := compressionTypes[rollingArchiveGzip]
+
+       archiveName := compressionType.rollingArchiveTypeName("log", false)
+
+       if archiveName != "log.tar.gz" {
+               t.Fatalf("archive name should be log.tar.gz but got %v", 
archiveName)
+       }
+}
+
+func TestRollingFileWriter(t *testing.T) {
+       t.Logf("Starting rolling file writer tests")
+       NewFileWriterTester(rollingfileWriterTests, rollingFileWriterGetter, 
t).test()
+}
+
+//===============================================================
+
+func rollingFileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, 
error) {
+       if testCase.rollingType == rollingTypeSize {
+               return NewRollingFileWriterSize(testCase.fileName, 
testCase.archiveType, testCase.archivePath, testCase.fileSize, 
testCase.maxRolls, testCase.nameMode, testCase.archiveExploded)
+       } else if testCase.rollingType == rollingTypeTime {
+               return NewRollingFileWriterTime(testCase.fileName, 
testCase.archiveType, testCase.archivePath, -1, testCase.datePattern, 
testCase.nameMode, testCase.archiveExploded, false)
+       }
+
+       return nil, fmt.Errorf("incorrect rollingType")
+}
+
+//===============================================================
+var rollingfileWriterTests = []*fileWriterTestCase{
+       createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 
1, []string{"log.testlog"}, rollingNameModePostfix, rollingArchiveNone, false, 
""),
+       createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 
2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{"1.log.testlog"}, 
"log.testlog", 10, 10, 2, []string{"log.testlog", "1.log.testlog", 
"2.log.testlog"}, rollingNameModePrefix, rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{"log.testlog.1"}, 
"log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.2"}, 
rollingNameModePostfix, rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 1, 
2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{"log.testlog.9"}, 
"log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.10"}, 
rollingNameModePostfix, rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{"log.testlog.a", 
"log.testlog.1b"}, "log.testlog", 10, 1, 2, []string{"log.testlog", 
"log.testlog.1", "log.testlog.a", "log.testlog.1b"}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 
10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix, rollingArchiveNone, 
false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 
10, 2, []string{`dir/log.testlog`, `dir/1.log.testlog`}, rollingNameModePrefix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{`dir/dir/log.testlog.1`}, 
`dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, 
`dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       
createRollingSizeFileWriterTestCase([]string{`dir/dir/dir/log.testlog.1`}, 
`dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, 
`dir/dir/dir/log.testlog.2`}, rollingNameModePostfix, rollingArchiveNone, 
false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `./log.testlog`, 10, 1, 
2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, 
`log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, 
rollingNameModePostfix, rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{"dir/dir/log.testlog.a", 
"dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, 
[]string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", 
"dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 
10, 10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 
10, 10, 2, []string{`dir/log.testlog`, `dir/log.testlog.1`}, 
rollingNameModePostfix, rollingArchiveNone, false, ""),
+       
createRollingSizeFileWriterTestCase([]string{`././dir/dir/log.testlog.1`}, 
`dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, 
`dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       
createRollingSizeFileWriterTestCase([]string{`././dir/dir/dir/log.testlog.1`}, 
`dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, 
`dir/dir/dir/log.testlog.2`}, rollingNameModePostfix, rollingArchiveNone, 
false, ""),
+       createRollingSizeFileWriterTestCase([]string{}, `././log.testlog`, 10, 
1, 2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix, 
rollingArchiveNone, false, ""),
+       createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, 
`log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, 
rollingNameModePostfix, rollingArchiveNone, false, ""),
+       
createRollingSizeFileWriterTestCase([]string{"././dir/dir/log.testlog.a", 
"././dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, 
[]string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", 
"dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix, 
rollingArchiveNone, true, ""),
+       createRollingSizeFileWriterTestCase([]string{"log.testlog", 
"log.testlog.1"}, "log.testlog", 10, 1, 2, []string{"log.testlog", 
"log.testlog.2", "dir/log.testlog.1.zip"}, rollingNameModePostfix, 
rollingArchiveZip, true, "dir"),
+       // ====================
+}

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/writers_smtpwriter.go
----------------------------------------------------------------------
diff --git a/traffic_stats/vendor/github.com/cihub/seelog 
b/traffic_stats/vendor/github.com/cihub/seelog
deleted file mode 160000
index 175e6e3..0000000
--- a/traffic_stats/vendor/github.com/cihub/seelog
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 175e6e3d439fe2e1cee7ab652b12eb546c145a13
diff --git a/traffic_stats/vendor/github.com/cihub/seelog/writers_smtpwriter.go 
b/traffic_stats/vendor/github.com/cihub/seelog/writers_smtpwriter.go
new file mode 100644
index 0000000..31b7943
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/writers_smtpwriter.go
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, 
this
+//    list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
FOR
+// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package seelog
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "errors"
+       "fmt"
+       "io/ioutil"
+       "net/smtp"
+       "path/filepath"
+       "strings"
+)
+
+const (
+       // Default subject phrase for sending emails.
+       DefaultSubjectPhrase = "Diagnostic message from server: "
+
+       // Message subject pattern composed according to RFC 5321.
+       rfc5321SubjectPattern = "From: %s <%s>\nSubject: %s\n\n"
+)
+
+// smtpWriter is used to send emails via given SMTP-server.
+type smtpWriter struct {
+       auth               smtp.Auth
+       hostName           string
+       hostPort           string
+       hostNameWithPort   string
+       senderAddress      string
+       senderName         string
+       recipientAddresses []string
+       caCertDirPaths     []string
+       mailHeaders        []string
+       subject            string
+}
+
+// NewSMTPWriter returns a new SMTP-writer.
+func NewSMTPWriter(sa, sn string, ras []string, hn, hp, un, pwd string, cacdps 
[]string, subj string, headers []string) *smtpWriter {
+       return &smtpWriter{
+               auth:               smtp.PlainAuth("", un, pwd, hn),
+               hostName:           hn,
+               hostPort:           hp,
+               hostNameWithPort:   fmt.Sprintf("%s:%s", hn, hp),
+               senderAddress:      sa,
+               senderName:         sn,
+               recipientAddresses: ras,
+               caCertDirPaths:     cacdps,
+               subject:            subj,
+               mailHeaders:        headers,
+       }
+}
+
+func prepareMessage(senderAddr, senderName, subject string, body []byte, 
headers []string) []byte {
+       headerLines := fmt.Sprintf(rfc5321SubjectPattern, senderName, 
senderAddr, subject)
+       // Build header lines if configured.
+       if headers != nil && len(headers) > 0 {
+               headerLines += strings.Join(headers, "\n")
+               headerLines += "\n"
+       }
+       return append([]byte(headerLines), body...)
+}
+
+// getTLSConfig gets paths of PEM files with certificates,
+// host server name and tries to create an appropriate TLS.Config.
+func getTLSConfig(pemFileDirPaths []string, hostName string) (config 
*tls.Config, err error) {
+       if pemFileDirPaths == nil || len(pemFileDirPaths) == 0 {
+               err = errors.New("invalid PEM file paths")
+               return
+       }
+       pemEncodedContent := []byte{}
+       var (
+               e     error
+               bytes []byte
+       )
+       // Create a file-filter-by-extension, set aside non-pem files.
+       pemFilePathFilter := func(fp string) bool {
+               if filepath.Ext(fp) == ".pem" {
+                       return true
+               }
+               return false
+       }
+       for _, pemFileDirPath := range pemFileDirPaths {
+               pemFilePaths, err := getDirFilePaths(pemFileDirPath, 
pemFilePathFilter, false)
+               if err != nil {
+                       return nil, err
+               }
+
+               // Put together all the PEM files to decode them as a whole 
byte slice.
+               for _, pfp := range pemFilePaths {
+                       if bytes, e = ioutil.ReadFile(pfp); e == nil {
+                               pemEncodedContent = append(pemEncodedContent, 
bytes...)
+                       } else {
+                               return nil, fmt.Errorf("cannot read file: %s: 
%s", pfp, e.Error())
+                       }
+               }
+       }
+       config = &tls.Config{RootCAs: x509.NewCertPool(), ServerName: hostName}
+       isAppended := config.RootCAs.AppendCertsFromPEM(pemEncodedContent)
+       if !isAppended {
+               // Extract this into a separate error.
+               err = errors.New("invalid PEM content")
+               return
+       }
+       return
+}
+
+// SendMail accepts TLS configuration, connects to the server at addr,
+// switches to TLS if possible, authenticates with mechanism a if possible,
+// and then sends an email from address from, to addresses to, with message 
msg.
+func sendMailWithTLSConfig(config *tls.Config, addr string, a smtp.Auth, from 
string, to []string, msg []byte) error {
+       c, err := smtp.Dial(addr)
+       if err != nil {
+               return err
+       }
+       // Check if the server supports STARTTLS extension.
+       if ok, _ := c.Extension("STARTTLS"); ok {
+               if err = c.StartTLS(config); err != nil {
+                       return err
+               }
+       }
+       // Check if the server supports AUTH extension and use given smtp.Auth.
+       if a != nil {
+               if isSupported, _ := c.Extension("AUTH"); isSupported {
+                       if err = c.Auth(a); err != nil {
+                               return err
+                       }
+               }
+       }
+       // Portion of code from the official smtp.SendMail function,
+       // see http://golang.org/src/pkg/net/smtp/smtp.go.
+       if err = c.Mail(from); err != nil {
+               return err
+       }
+       for _, addr := range to {
+               if err = c.Rcpt(addr); err != nil {
+                       return err
+               }
+       }
+       w, err := c.Data()
+       if err != nil {
+               return err
+       }
+       _, err = w.Write(msg)
+       if err != nil {
+               return err
+       }
+       err = w.Close()
+       if err != nil {
+               return err
+       }
+       return c.Quit()
+}
+
+// Write pushes a text message properly composed according to RFC 5321
+// to a post server, which sends it to the recipients.
+func (smtpw *smtpWriter) Write(data []byte) (int, error) {
+       var err error
+
+       if smtpw.caCertDirPaths == nil {
+               err = smtp.SendMail(
+                       smtpw.hostNameWithPort,
+                       smtpw.auth,
+                       smtpw.senderAddress,
+                       smtpw.recipientAddresses,
+                       prepareMessage(smtpw.senderAddress, smtpw.senderName, 
smtpw.subject, data, smtpw.mailHeaders),
+               )
+       } else {
+               config, e := getTLSConfig(smtpw.caCertDirPaths, smtpw.hostName)
+               if e != nil {
+                       return 0, e
+               }
+               err = sendMailWithTLSConfig(
+                       config,
+                       smtpw.hostNameWithPort,
+                       smtpw.auth,
+                       smtpw.senderAddress,
+                       smtpw.recipientAddresses,
+                       prepareMessage(smtpw.senderAddress, smtpw.senderName, 
smtpw.subject, data, smtpw.mailHeaders),
+               )
+       }
+       if err != nil {
+               return 0, err
+       }
+       return len(data), nil
+}
+
+// Close closes down SMTP-connection.
+func (smtpw *smtpWriter) Close() error {
+       // Do nothing as Write method opens and closes connection automatically.
+       return nil
+}

Reply via email to