You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2017/01/24 20:56:20 UTC
[09/13] incubator-trafficcontrol git commit: Vendored
github.com/cihub/seelog.
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser.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/cfg_parser.go b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser.go
new file mode 100644
index 0000000..921bc16
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser.go
@@ -0,0 +1,1269 @@
+// 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"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Names of elements of seelog config.
+const (
+ seelogConfigID = "seelog"
+ outputsID = "outputs"
+ formatsID = "formats"
+ minLevelID = "minlevel"
+ maxLevelID = "maxlevel"
+ levelsID = "levels"
+ exceptionsID = "exceptions"
+ exceptionID = "exception"
+ funcPatternID = "funcpattern"
+ filePatternID = "filepattern"
+ formatID = "format"
+ formatAttrID = "format"
+ formatKeyAttrID = "id"
+ outputFormatID = "formatid"
+ pathID = "path"
+ fileWriterID = "file"
+ smtpWriterID = "smtp"
+ senderaddressID = "senderaddress"
+ senderNameID = "sendername"
+ recipientID = "recipient"
+ mailHeaderID = "header"
+ mailHeaderNameID = "name"
+ mailHeaderValueID = "value"
+ addressID = "address"
+ hostNameID = "hostname"
+ hostPortID = "hostport"
+ userNameID = "username"
+ userPassID = "password"
+ cACertDirpathID = "cacertdirpath"
+ subjectID = "subject"
+ splitterDispatcherID = "splitter"
+ consoleWriterID = "console"
+ customReceiverID = "custom"
+ customNameAttrID = "name"
+ customNameDataAttrPrefix = "data-"
+ filterDispatcherID = "filter"
+ filterLevelsAttrID = "levels"
+ rollingfileWriterID = "rollingfile"
+ rollingFileTypeAttr = "type"
+ rollingFilePathAttr = "filename"
+ rollingFileMaxSizeAttr = "maxsize"
+ rollingFileMaxRollsAttr = "maxrolls"
+ rollingFileNameModeAttr = "namemode"
+ rollingFileDataPatternAttr = "datepattern"
+ rollingFileArchiveAttr = "archivetype"
+ rollingFileArchivePathAttr = "archivepath"
+ rollingFileArchiveExplodedAttr = "archiveexploded"
+ rollingFileFullNameAttr = "fullname"
+ bufferedWriterID = "buffered"
+ bufferedSizeAttr = "size"
+ bufferedFlushPeriodAttr = "flushperiod"
+ loggerTypeFromStringAttr = "type"
+ asyncLoggerIntervalAttr = "asyncinterval"
+ adaptLoggerMinIntervalAttr = "mininterval"
+ adaptLoggerMaxIntervalAttr = "maxinterval"
+ adaptLoggerCriticalMsgCountAttr = "critmsgcount"
+ predefinedPrefix = "std:"
+ connWriterID = "conn"
+ connWriterAddrAttr = "addr"
+ connWriterNetAttr = "net"
+ connWriterReconnectOnMsgAttr = "reconnectonmsg"
+ connWriterUseTLSAttr = "tls"
+ connWriterInsecureSkipVerifyAttr = "insecureskipverify"
+)
+
+// CustomReceiverProducer is the signature of the function CfgParseParams needs to create
+// custom receivers.
+type CustomReceiverProducer func(CustomReceiverInitArgs) (CustomReceiver, error)
+
+// CfgParseParams represent specific parse options or flags used by parser. It is used if seelog parser needs
+// some special directives or additional info to correctly parse a config.
+type CfgParseParams struct {
+ // CustomReceiverProducers expose the same functionality as RegisterReceiver func
+ // but only in the scope (context) of the config parse func instead of a global package scope.
+ //
+ // It means that if you use custom receivers in your code, you may either register them globally once with
+ // RegisterReceiver or you may call funcs like LoggerFromParamConfigAsFile (with 'ParamConfig')
+ // and use CustomReceiverProducers to provide custom producer funcs.
+ //
+ // A producer func is called when config parser processes a '<custom>' element. It takes the 'name' attribute
+ // of the element and tries to find a match in two places:
+ // 1) CfgParseParams.CustomReceiverProducers map
+ // 2) Global type map, filled by RegisterReceiver
+ //
+ // If a match is found in the CustomReceiverProducers map, parser calls the corresponding producer func
+ // passing the init args to it. The func takes exactly the same args as CustomReceiver.AfterParse.
+ // The producer func must return a correct receiver or an error. If case of error, seelog will behave
+ // in the same way as with any other config error.
+ //
+ // You may use this param to set custom producers in case you need to pass some context when instantiating
+ // a custom receiver or if you frequently change custom receivers with different parameters or in any other
+ // situation where package-level registering (RegisterReceiver) is not an option for you.
+ CustomReceiverProducers map[string]CustomReceiverProducer
+}
+
+func (cfg *CfgParseParams) String() string {
+ return fmt.Sprintf("CfgParams: {custom_recs=%d}", len(cfg.CustomReceiverProducers))
+}
+
+type elementMapEntry struct {
+ constructor func(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error)
+}
+
+var elementMap map[string]elementMapEntry
+var predefinedFormats map[string]*formatter
+
+func init() {
+ elementMap = map[string]elementMapEntry{
+ fileWriterID: {createfileWriter},
+ splitterDispatcherID: {createSplitter},
+ customReceiverID: {createCustomReceiver},
+ filterDispatcherID: {createFilter},
+ consoleWriterID: {createConsoleWriter},
+ rollingfileWriterID: {createRollingFileWriter},
+ bufferedWriterID: {createbufferedWriter},
+ smtpWriterID: {createSMTPWriter},
+ connWriterID: {createconnWriter},
+ }
+
+ err := fillPredefinedFormats()
+ if err != nil {
+ panic(fmt.Sprintf("Seelog couldn't start: predefined formats creation failed. Error: %s", err.Error()))
+ }
+}
+
+func fillPredefinedFormats() error {
+ predefinedFormatsWithoutPrefix := map[string]string{
+ "xml-debug": `<time>%Ns</time><lev>%Lev</lev><msg>%Msg</msg><path>%RelFile</path><func>%Func</func><line>%Line</line>`,
+ "xml-debug-short": `<t>%Ns</t><l>%l</l><m>%Msg</m><p>%RelFile</p><f>%Func</f>`,
+ "xml": `<time>%Ns</time><lev>%Lev</lev><msg>%Msg</msg>`,
+ "xml-short": `<t>%Ns</t><l>%l</l><m>%Msg</m>`,
+
+ "json-debug": `{"time":%Ns,"lev":"%Lev","msg":"%Msg","path":"%RelFile","func":"%Func","line":"%Line"}`,
+ "json-debug-short": `{"t":%Ns,"l":"%Lev","m":"%Msg","p":"%RelFile","f":"%Func"}`,
+ "json": `{"time":%Ns,"lev":"%Lev","msg":"%Msg"}`,
+ "json-short": `{"t":%Ns,"l":"%Lev","m":"%Msg"}`,
+
+ "debug": `[%LEVEL] %RelFile:%Func.%Line %Date %Time %Msg%n`,
+ "debug-short": `[%LEVEL] %Date %Time %Msg%n`,
+ "fast": `%Ns %l %Msg%n`,
+ }
+
+ predefinedFormats = make(map[string]*formatter)
+
+ for formatKey, format := range predefinedFormatsWithoutPrefix {
+ formatter, err := NewFormatter(format)
+ if err != nil {
+ return err
+ }
+
+ predefinedFormats[predefinedPrefix+formatKey] = formatter
+ }
+
+ return nil
+}
+
+// configFromXMLDecoder parses data from a given XML decoder.
+// Returns parsed config which can be used to create logger in case no errors occured.
+// Returns error if format is incorrect or anything happened.
+func configFromXMLDecoder(xmlParser *xml.Decoder, rootNode xml.Token) (*configForParsing, error) {
+ return configFromXMLDecoderWithConfig(xmlParser, rootNode, nil)
+}
+
+// configFromXMLDecoderWithConfig parses data from a given XML decoder.
+// Returns parsed config which can be used to create logger in case no errors occured.
+// Returns error if format is incorrect or anything happened.
+func configFromXMLDecoderWithConfig(xmlParser *xml.Decoder, rootNode xml.Token, cfg *CfgParseParams) (*configForParsing, error) {
+ _, ok := rootNode.(xml.StartElement)
+ if !ok {
+ return nil, errors.New("rootNode must be XML startElement")
+ }
+
+ config, err := unmarshalNode(xmlParser, rootNode)
+ if err != nil {
+ return nil, err
+ }
+ if config == nil {
+ return nil, errors.New("xml has no content")
+ }
+
+ return configFromXMLNodeWithConfig(config, cfg)
+}
+
+// configFromReader parses data from a given reader.
+// Returns parsed config which can be used to create logger in case no errors occured.
+// Returns error if format is incorrect or anything happened.
+func configFromReader(reader io.Reader) (*configForParsing, error) {
+ return configFromReaderWithConfig(reader, nil)
+}
+
+// configFromReaderWithConfig parses data from a given reader.
+// Returns parsed config which can be used to create logger in case no errors occured.
+// Returns error if format is incorrect or anything happened.
+func configFromReaderWithConfig(reader io.Reader, cfg *CfgParseParams) (*configForParsing, error) {
+ config, err := unmarshalConfig(reader)
+ if err != nil {
+ return nil, err
+ }
+
+ if config.name != seelogConfigID {
+ return nil, errors.New("root xml tag must be '" + seelogConfigID + "'")
+ }
+
+ return configFromXMLNodeWithConfig(config, cfg)
+}
+
+func configFromXMLNodeWithConfig(config *xmlNode, cfg *CfgParseParams) (*configForParsing, error) {
+ err := checkUnexpectedAttribute(
+ config,
+ minLevelID,
+ maxLevelID,
+ levelsID,
+ loggerTypeFromStringAttr,
+ asyncLoggerIntervalAttr,
+ adaptLoggerMinIntervalAttr,
+ adaptLoggerMaxIntervalAttr,
+ adaptLoggerCriticalMsgCountAttr,
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ err = checkExpectedElements(config, optionalElement(outputsID), optionalElement(formatsID), optionalElement(exceptionsID))
+ if err != nil {
+ return nil, err
+ }
+
+ constraints, err := getConstraints(config)
+ if err != nil {
+ return nil, err
+ }
+
+ exceptions, err := getExceptions(config)
+ if err != nil {
+ return nil, err
+ }
+ err = checkDistinctExceptions(exceptions)
+ if err != nil {
+ return nil, err
+ }
+
+ formats, err := getFormats(config)
+ if err != nil {
+ return nil, err
+ }
+
+ dispatcher, err := getOutputsTree(config, formats, cfg)
+ if err != nil {
+ // If we open several files, but then fail to parse the config, we should close
+ // those files before reporting that config is invalid.
+ if dispatcher != nil {
+ dispatcher.Close()
+ }
+
+ return nil, err
+ }
+
+ loggerType, logData, err := getloggerTypeFromStringData(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return newFullLoggerConfig(constraints, exceptions, dispatcher, loggerType, logData, cfg)
+}
+
+func getConstraints(node *xmlNode) (logLevelConstraints, error) {
+ minLevelStr, isMinLevel := node.attributes[minLevelID]
+ maxLevelStr, isMaxLevel := node.attributes[maxLevelID]
+ levelsStr, isLevels := node.attributes[levelsID]
+
+ if isLevels && (isMinLevel && isMaxLevel) {
+ return nil, errors.New("for level declaration use '" + levelsID + "'' OR '" + minLevelID +
+ "', '" + maxLevelID + "'")
+ }
+
+ offString := LogLevel(Off).String()
+
+ if (isLevels && strings.TrimSpace(levelsStr) == offString) ||
+ (isMinLevel && !isMaxLevel && minLevelStr == offString) {
+
+ return NewOffConstraints()
+ }
+
+ if isLevels {
+ levels, err := parseLevels(levelsStr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListConstraints(levels)
+ }
+
+ var minLevel = LogLevel(TraceLvl)
+ if isMinLevel {
+ found := true
+ minLevel, found = LogLevelFromString(minLevelStr)
+ if !found {
+ return nil, errors.New("declared " + minLevelID + " not found: " + minLevelStr)
+ }
+ }
+
+ var maxLevel = LogLevel(CriticalLvl)
+ if isMaxLevel {
+ found := true
+ maxLevel, found = LogLevelFromString(maxLevelStr)
+ if !found {
+ return nil, errors.New("declared " + maxLevelID + " not found: " + maxLevelStr)
+ }
+ }
+
+ return NewMinMaxConstraints(minLevel, maxLevel)
+}
+
+func parseLevels(str string) ([]LogLevel, error) {
+ levelsStrArr := strings.Split(strings.Replace(str, " ", "", -1), ",")
+ var levels []LogLevel
+ for _, levelStr := range levelsStrArr {
+ level, found := LogLevelFromString(levelStr)
+ if !found {
+ return nil, errors.New("declared level not found: " + levelStr)
+ }
+
+ levels = append(levels, level)
+ }
+
+ return levels, nil
+}
+
+func getExceptions(config *xmlNode) ([]*LogLevelException, error) {
+ var exceptions []*LogLevelException
+
+ var exceptionsNode *xmlNode
+ for _, child := range config.children {
+ if child.name == exceptionsID {
+ exceptionsNode = child
+ break
+ }
+ }
+
+ if exceptionsNode == nil {
+ return exceptions, nil
+ }
+
+ err := checkUnexpectedAttribute(exceptionsNode)
+ if err != nil {
+ return nil, err
+ }
+
+ err = checkExpectedElements(exceptionsNode, multipleMandatoryElements("exception"))
+ if err != nil {
+ return nil, err
+ }
+
+ for _, exceptionNode := range exceptionsNode.children {
+ if exceptionNode.name != exceptionID {
+ return nil, errors.New("incorrect nested element in exceptions section: " + exceptionNode.name)
+ }
+
+ err := checkUnexpectedAttribute(exceptionNode, minLevelID, maxLevelID, levelsID, funcPatternID, filePatternID)
+ if err != nil {
+ return nil, err
+ }
+
+ constraints, err := getConstraints(exceptionNode)
+ if err != nil {
+ return nil, errors.New("incorrect " + exceptionsID + " node: " + err.Error())
+ }
+
+ funcPattern, isFuncPattern := exceptionNode.attributes[funcPatternID]
+ filePattern, isFilePattern := exceptionNode.attributes[filePatternID]
+ if !isFuncPattern {
+ funcPattern = "*"
+ }
+ if !isFilePattern {
+ filePattern = "*"
+ }
+
+ exception, err := NewLogLevelException(funcPattern, filePattern, constraints)
+ if err != nil {
+ return nil, errors.New("incorrect exception node: " + err.Error())
+ }
+
+ exceptions = append(exceptions, exception)
+ }
+
+ return exceptions, nil
+}
+
+func checkDistinctExceptions(exceptions []*LogLevelException) error {
+ for i, exception := range exceptions {
+ for j, exception1 := range exceptions {
+ if i == j {
+ continue
+ }
+
+ if exception.FuncPattern() == exception1.FuncPattern() &&
+ exception.FilePattern() == exception1.FilePattern() {
+
+ return fmt.Errorf("there are two or more duplicate exceptions. Func: %v, file %v",
+ exception.FuncPattern(), exception.FilePattern())
+ }
+ }
+ }
+
+ return nil
+}
+
+func getFormats(config *xmlNode) (map[string]*formatter, error) {
+ formats := make(map[string]*formatter, 0)
+
+ var formatsNode *xmlNode
+ for _, child := range config.children {
+ if child.name == formatsID {
+ formatsNode = child
+ break
+ }
+ }
+
+ if formatsNode == nil {
+ return formats, nil
+ }
+
+ err := checkUnexpectedAttribute(formatsNode)
+ if err != nil {
+ return nil, err
+ }
+
+ err = checkExpectedElements(formatsNode, multipleMandatoryElements("format"))
+ if err != nil {
+ return nil, err
+ }
+
+ for _, formatNode := range formatsNode.children {
+ if formatNode.name != formatID {
+ return nil, errors.New("incorrect nested element in " + formatsID + " section: " + formatNode.name)
+ }
+
+ err := checkUnexpectedAttribute(formatNode, formatKeyAttrID, formatID)
+ if err != nil {
+ return nil, err
+ }
+
+ id, isID := formatNode.attributes[formatKeyAttrID]
+ formatStr, isFormat := formatNode.attributes[formatAttrID]
+ if !isID {
+ return nil, errors.New("format has no '" + formatKeyAttrID + "' attribute")
+ }
+ if !isFormat {
+ return nil, errors.New("format[" + id + "] has no '" + formatAttrID + "' attribute")
+ }
+
+ formatter, err := NewFormatter(formatStr)
+ if err != nil {
+ return nil, err
+ }
+
+ formats[id] = formatter
+ }
+
+ return formats, nil
+}
+
+func getloggerTypeFromStringData(config *xmlNode) (logType loggerTypeFromString, logData interface{}, err error) {
+ logTypeStr, loggerTypeExists := config.attributes[loggerTypeFromStringAttr]
+
+ if !loggerTypeExists {
+ return defaultloggerTypeFromString, nil, nil
+ }
+
+ logType, found := getLoggerTypeFromString(logTypeStr)
+
+ if !found {
+ return 0, nil, fmt.Errorf("unknown logger type: %s", logTypeStr)
+ }
+
+ if logType == asyncTimerloggerTypeFromString {
+ intervalStr, intervalExists := config.attributes[asyncLoggerIntervalAttr]
+ if !intervalExists {
+ return 0, nil, newMissingArgumentError(config.name, asyncLoggerIntervalAttr)
+ }
+
+ interval, err := strconv.ParseUint(intervalStr, 10, 32)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ logData = asyncTimerLoggerData{uint32(interval)}
+ } else if logType == adaptiveLoggerTypeFromString {
+
+ // Min interval
+ minIntStr, minIntExists := config.attributes[adaptLoggerMinIntervalAttr]
+ if !minIntExists {
+ return 0, nil, newMissingArgumentError(config.name, adaptLoggerMinIntervalAttr)
+ }
+ minInterval, err := strconv.ParseUint(minIntStr, 10, 32)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ // Max interval
+ maxIntStr, maxIntExists := config.attributes[adaptLoggerMaxIntervalAttr]
+ if !maxIntExists {
+ return 0, nil, newMissingArgumentError(config.name, adaptLoggerMaxIntervalAttr)
+ }
+ maxInterval, err := strconv.ParseUint(maxIntStr, 10, 32)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ // Critical msg count
+ criticalMsgCountStr, criticalMsgCountExists := config.attributes[adaptLoggerCriticalMsgCountAttr]
+ if !criticalMsgCountExists {
+ return 0, nil, newMissingArgumentError(config.name, adaptLoggerCriticalMsgCountAttr)
+ }
+ criticalMsgCount, err := strconv.ParseUint(criticalMsgCountStr, 10, 32)
+ if err != nil {
+ return 0, nil, err
+ }
+
+ logData = adaptiveLoggerData{uint32(minInterval), uint32(maxInterval), uint32(criticalMsgCount)}
+ }
+
+ return logType, logData, nil
+}
+
+func getOutputsTree(config *xmlNode, formats map[string]*formatter, cfg *CfgParseParams) (dispatcherInterface, error) {
+ var outputsNode *xmlNode
+ for _, child := range config.children {
+ if child.name == outputsID {
+ outputsNode = child
+ break
+ }
+ }
+
+ if outputsNode != nil {
+ err := checkUnexpectedAttribute(outputsNode, outputFormatID)
+ if err != nil {
+ return nil, err
+ }
+
+ formatter, err := getCurrentFormat(outputsNode, DefaultFormatter, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ output, err := createSplitter(outputsNode, formatter, formats, cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ dispatcher, ok := output.(dispatcherInterface)
+ if ok {
+ return dispatcher, nil
+ }
+ }
+
+ console, err := NewConsoleWriter()
+ if err != nil {
+ return nil, err
+ }
+ return NewSplitDispatcher(DefaultFormatter, []interface{}{console})
+}
+
+func getCurrentFormat(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter) (*formatter, error) {
+ formatID, isFormatID := node.attributes[outputFormatID]
+ if !isFormatID {
+ return formatFromParent, nil
+ }
+
+ format, ok := formats[formatID]
+ if ok {
+ return format, nil
+ }
+
+ // Test for predefined format match
+ pdFormat, pdOk := predefinedFormats[formatID]
+
+ if !pdOk {
+ return nil, errors.New("formatid = '" + formatID + "' doesn't exist")
+ }
+
+ return pdFormat, nil
+}
+
+func createInnerReceivers(node *xmlNode, format *formatter, formats map[string]*formatter, cfg *CfgParseParams) ([]interface{}, error) {
+ var outputs []interface{}
+ for _, childNode := range node.children {
+ entry, ok := elementMap[childNode.name]
+ if !ok {
+ return nil, errors.New("unnknown tag '" + childNode.name + "' in outputs section")
+ }
+
+ output, err := entry.constructor(childNode, format, formats, cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ outputs = append(outputs, output)
+ }
+
+ return outputs, nil
+}
+
+func createSplitter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID)
+ if err != nil {
+ return nil, err
+ }
+
+ if !node.hasChildren() {
+ return nil, errNodeMustHaveChildren
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ receivers, err := createInnerReceivers(node, currentFormat, formats, cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewSplitDispatcher(currentFormat, receivers)
+}
+
+func createCustomReceiver(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ dataCustomPrefixes := make(map[string]string)
+ // Expecting only 'formatid', 'name' and 'data-' attrs
+ for attr, attrval := range node.attributes {
+ isExpected := false
+ if attr == outputFormatID ||
+ attr == customNameAttrID {
+ isExpected = true
+ }
+ if strings.HasPrefix(attr, customNameDataAttrPrefix) {
+ dataCustomPrefixes[attr[len(customNameDataAttrPrefix):]] = attrval
+ isExpected = true
+ }
+ if !isExpected {
+ return nil, newUnexpectedAttributeError(node.name, attr)
+ }
+ }
+
+ if node.hasChildren() {
+ return nil, errNodeCannotHaveChildren
+ }
+ customName, hasCustomName := node.attributes[customNameAttrID]
+ if !hasCustomName {
+ return nil, newMissingArgumentError(node.name, customNameAttrID)
+ }
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+ args := CustomReceiverInitArgs{
+ XmlCustomAttrs: dataCustomPrefixes,
+ }
+
+ if cfg != nil && cfg.CustomReceiverProducers != nil {
+ if prod, ok := cfg.CustomReceiverProducers[customName]; ok {
+ rec, err := prod(args)
+ if err != nil {
+ return nil, err
+ }
+ creceiver, err := NewCustomReceiverDispatcherByValue(currentFormat, rec, customName, args)
+ if err != nil {
+ return nil, err
+ }
+ err = rec.AfterParse(args)
+ if err != nil {
+ return nil, err
+ }
+ return creceiver, nil
+ }
+ }
+
+ return NewCustomReceiverDispatcher(currentFormat, customName, args)
+}
+
+func createFilter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID, filterLevelsAttrID)
+ if err != nil {
+ return nil, err
+ }
+
+ if !node.hasChildren() {
+ return nil, errNodeMustHaveChildren
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ levelsStr, isLevels := node.attributes[filterLevelsAttrID]
+ if !isLevels {
+ return nil, newMissingArgumentError(node.name, filterLevelsAttrID)
+ }
+
+ levels, err := parseLevels(levelsStr)
+ if err != nil {
+ return nil, err
+ }
+
+ receivers, err := createInnerReceivers(node, currentFormat, formats, cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFilterDispatcher(currentFormat, receivers, levels...)
+}
+
+func createfileWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID, pathID)
+ if err != nil {
+ return nil, err
+ }
+
+ if node.hasChildren() {
+ return nil, errNodeCannotHaveChildren
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ path, isPath := node.attributes[pathID]
+ if !isPath {
+ return nil, newMissingArgumentError(node.name, pathID)
+ }
+
+ fileWriter, err := NewFileWriter(path)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFormattedWriter(fileWriter, currentFormat)
+}
+
+// Creates new SMTP writer if encountered in the config file.
+func createSMTPWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID, senderaddressID, senderNameID, hostNameID, hostPortID, userNameID, userPassID, subjectID)
+ if err != nil {
+ return nil, err
+ }
+ // Node must have children.
+ if !node.hasChildren() {
+ return nil, errNodeMustHaveChildren
+ }
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+ senderAddress, ok := node.attributes[senderaddressID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, senderaddressID)
+ }
+ senderName, ok := node.attributes[senderNameID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, senderNameID)
+ }
+ // Process child nodes scanning for recipient email addresses and/or CA certificate paths.
+ var recipientAddresses []string
+ var caCertDirPaths []string
+ var mailHeaders []string
+ for _, childNode := range node.children {
+ switch childNode.name {
+ // Extract recipient address from child nodes.
+ case recipientID:
+ address, ok := childNode.attributes[addressID]
+ if !ok {
+ return nil, newMissingArgumentError(childNode.name, addressID)
+ }
+ recipientAddresses = append(recipientAddresses, address)
+ // Extract CA certificate file path from child nodes.
+ case cACertDirpathID:
+ path, ok := childNode.attributes[pathID]
+ if !ok {
+ return nil, newMissingArgumentError(childNode.name, pathID)
+ }
+ caCertDirPaths = append(caCertDirPaths, path)
+
+ // Extract email headers from child nodes.
+ case mailHeaderID:
+ headerName, ok := childNode.attributes[mailHeaderNameID]
+ if !ok {
+ return nil, newMissingArgumentError(childNode.name, mailHeaderNameID)
+ }
+
+ headerValue, ok := childNode.attributes[mailHeaderValueID]
+ if !ok {
+ return nil, newMissingArgumentError(childNode.name, mailHeaderValueID)
+ }
+
+ // Build header line
+ mailHeaders = append(mailHeaders, fmt.Sprintf("%s: %s", headerName, headerValue))
+ default:
+ return nil, newUnexpectedChildElementError(childNode.name)
+ }
+ }
+ hostName, ok := node.attributes[hostNameID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, hostNameID)
+ }
+
+ hostPort, ok := node.attributes[hostPortID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, hostPortID)
+ }
+
+ // Check if the string can really be converted into int.
+ if _, err := strconv.Atoi(hostPort); err != nil {
+ return nil, errors.New("invalid host port number")
+ }
+
+ userName, ok := node.attributes[userNameID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, userNameID)
+ }
+
+ userPass, ok := node.attributes[userPassID]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, userPassID)
+ }
+
+ // subject is optionally set by configuration.
+ // default value is defined by DefaultSubjectPhrase constant in the writers_smtpwriter.go
+ var subjectPhrase = DefaultSubjectPhrase
+
+ subject, ok := node.attributes[subjectID]
+ if ok {
+ subjectPhrase = subject
+ }
+
+ smtpWriter := NewSMTPWriter(
+ senderAddress,
+ senderName,
+ recipientAddresses,
+ hostName,
+ hostPort,
+ userName,
+ userPass,
+ caCertDirPaths,
+ subjectPhrase,
+ mailHeaders,
+ )
+
+ return NewFormattedWriter(smtpWriter, currentFormat)
+}
+
+func createConsoleWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID)
+ if err != nil {
+ return nil, err
+ }
+
+ if node.hasChildren() {
+ return nil, errNodeCannotHaveChildren
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ consoleWriter, err := NewConsoleWriter()
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFormattedWriter(consoleWriter, currentFormat)
+}
+
+func createconnWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ if node.hasChildren() {
+ return nil, errNodeCannotHaveChildren
+ }
+
+ err := checkUnexpectedAttribute(node, outputFormatID, connWriterAddrAttr, connWriterNetAttr, connWriterReconnectOnMsgAttr, connWriterUseTLSAttr, connWriterInsecureSkipVerifyAttr)
+ if err != nil {
+ return nil, err
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ addr, isAddr := node.attributes[connWriterAddrAttr]
+ if !isAddr {
+ return nil, newMissingArgumentError(node.name, connWriterAddrAttr)
+ }
+
+ net, isNet := node.attributes[connWriterNetAttr]
+ if !isNet {
+ return nil, newMissingArgumentError(node.name, connWriterNetAttr)
+ }
+
+ reconnectOnMsg := false
+ reconnectOnMsgStr, isReconnectOnMsgStr := node.attributes[connWriterReconnectOnMsgAttr]
+ if isReconnectOnMsgStr {
+ if reconnectOnMsgStr == "true" {
+ reconnectOnMsg = true
+ } else if reconnectOnMsgStr == "false" {
+ reconnectOnMsg = false
+ } else {
+ return nil, errors.New("node '" + node.name + "' has incorrect '" + connWriterReconnectOnMsgAttr + "' attribute value")
+ }
+ }
+
+ useTLS := false
+ useTLSStr, isUseTLSStr := node.attributes[connWriterUseTLSAttr]
+ if isUseTLSStr {
+ if useTLSStr == "true" {
+ useTLS = true
+ } else if useTLSStr == "false" {
+ useTLS = false
+ } else {
+ return nil, errors.New("node '" + node.name + "' has incorrect '" + connWriterUseTLSAttr + "' attribute value")
+ }
+ if useTLS {
+ insecureSkipVerify := false
+ insecureSkipVerifyStr, isInsecureSkipVerify := node.attributes[connWriterInsecureSkipVerifyAttr]
+ if isInsecureSkipVerify {
+ if insecureSkipVerifyStr == "true" {
+ insecureSkipVerify = true
+ } else if insecureSkipVerifyStr == "false" {
+ insecureSkipVerify = false
+ } else {
+ return nil, errors.New("node '" + node.name + "' has incorrect '" + connWriterInsecureSkipVerifyAttr + "' attribute value")
+ }
+ }
+ config := tls.Config{InsecureSkipVerify: insecureSkipVerify}
+ connWriter := newTLSWriter(net, addr, reconnectOnMsg, &config)
+ return NewFormattedWriter(connWriter, currentFormat)
+ }
+ }
+
+ connWriter := NewConnWriter(net, addr, reconnectOnMsg)
+
+ return NewFormattedWriter(connWriter, currentFormat)
+}
+
+func createRollingFileWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ if node.hasChildren() {
+ return nil, errNodeCannotHaveChildren
+ }
+
+ rollingTypeStr, isRollingType := node.attributes[rollingFileTypeAttr]
+ if !isRollingType {
+ return nil, newMissingArgumentError(node.name, rollingFileTypeAttr)
+ }
+
+ rollingType, ok := rollingTypeFromString(rollingTypeStr)
+ if !ok {
+ return nil, errors.New("unknown rolling file type: " + rollingTypeStr)
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ path, isPath := node.attributes[rollingFilePathAttr]
+ if !isPath {
+ return nil, newMissingArgumentError(node.name, rollingFilePathAttr)
+ }
+
+ rollingArchiveStr, archiveAttrExists := node.attributes[rollingFileArchiveAttr]
+
+ var rArchiveType rollingArchiveType
+ var rArchivePath string
+ var rArchiveExploded bool = false
+ if !archiveAttrExists {
+ rArchiveType = rollingArchiveNone
+ rArchivePath = ""
+ } else {
+ rArchiveType, ok = rollingArchiveTypeFromString(rollingArchiveStr)
+ if !ok {
+ return nil, errors.New("unknown rolling archive type: " + rollingArchiveStr)
+ }
+
+ if rArchiveType == rollingArchiveNone {
+ rArchivePath = ""
+ } else {
+ if rArchiveExplodedAttr, ok := node.attributes[rollingFileArchiveExplodedAttr]; ok {
+ if rArchiveExploded, err = strconv.ParseBool(rArchiveExplodedAttr); err != nil {
+ return nil, fmt.Errorf("archive exploded should be true or false, but was %v",
+ rArchiveExploded)
+ }
+ }
+
+ rArchivePath, ok = node.attributes[rollingFileArchivePathAttr]
+ if ok {
+ if rArchivePath == "" {
+ return nil, fmt.Errorf("empty archive path is not supported")
+ }
+ } else {
+ if rArchiveExploded {
+ rArchivePath = rollingArchiveDefaultExplodedName
+
+ } else {
+ rArchivePath, err = rollingArchiveTypeDefaultName(rArchiveType, false)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+ }
+
+ nameMode := rollingNameMode(rollingNameModePostfix)
+ nameModeStr, ok := node.attributes[rollingFileNameModeAttr]
+ if ok {
+ mode, found := rollingNameModeFromString(nameModeStr)
+ if !found {
+ return nil, errors.New("unknown rolling filename mode: " + nameModeStr)
+ } else {
+ nameMode = mode
+ }
+ }
+
+ if rollingType == rollingTypeSize {
+ err := checkUnexpectedAttribute(node, outputFormatID, rollingFileTypeAttr, rollingFilePathAttr,
+ rollingFileMaxSizeAttr, rollingFileMaxRollsAttr, rollingFileArchiveAttr,
+ rollingFileArchivePathAttr, rollingFileArchiveExplodedAttr, rollingFileNameModeAttr)
+ if err != nil {
+ return nil, err
+ }
+
+ maxSizeStr, ok := node.attributes[rollingFileMaxSizeAttr]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, rollingFileMaxSizeAttr)
+ }
+
+ maxSize, err := strconv.ParseInt(maxSizeStr, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ maxRolls := 0
+ maxRollsStr, ok := node.attributes[rollingFileMaxRollsAttr]
+ if ok {
+ maxRolls, err = strconv.Atoi(maxRollsStr)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ rollingWriter, err := NewRollingFileWriterSize(path, rArchiveType, rArchivePath, maxSize, maxRolls, nameMode, rArchiveExploded)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFormattedWriter(rollingWriter, currentFormat)
+
+ } else if rollingType == rollingTypeTime {
+ err := checkUnexpectedAttribute(node, outputFormatID, rollingFileTypeAttr, rollingFilePathAttr,
+ rollingFileDataPatternAttr, rollingFileArchiveAttr, rollingFileMaxRollsAttr,
+ rollingFileArchivePathAttr, rollingFileArchiveExplodedAttr, rollingFileNameModeAttr,
+ rollingFileFullNameAttr)
+ if err != nil {
+ return nil, err
+ }
+
+ maxRolls := 0
+ maxRollsStr, ok := node.attributes[rollingFileMaxRollsAttr]
+ if ok {
+ maxRolls, err = strconv.Atoi(maxRollsStr)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ fullName := false
+ fn, ok := node.attributes[rollingFileFullNameAttr]
+ if ok {
+ if fn == "true" {
+ fullName = true
+ } else if fn == "false" {
+ fullName = false
+ } else {
+ return nil, errors.New("node '" + node.name + "' has incorrect '" + rollingFileFullNameAttr + "' attribute value")
+ }
+ }
+
+ dataPattern, ok := node.attributes[rollingFileDataPatternAttr]
+ if !ok {
+ return nil, newMissingArgumentError(node.name, rollingFileDataPatternAttr)
+ }
+
+ rollingWriter, err := NewRollingFileWriterTime(path, rArchiveType, rArchivePath, maxRolls, dataPattern, nameMode, rArchiveExploded, fullName)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFormattedWriter(rollingWriter, currentFormat)
+ }
+
+ return nil, errors.New("incorrect rolling writer type " + rollingTypeStr)
+}
+
+func createbufferedWriter(node *xmlNode, formatFromParent *formatter, formats map[string]*formatter, cfg *CfgParseParams) (interface{}, error) {
+ err := checkUnexpectedAttribute(node, outputFormatID, bufferedSizeAttr, bufferedFlushPeriodAttr)
+ if err != nil {
+ return nil, err
+ }
+
+ if !node.hasChildren() {
+ return nil, errNodeMustHaveChildren
+ }
+
+ currentFormat, err := getCurrentFormat(node, formatFromParent, formats)
+ if err != nil {
+ return nil, err
+ }
+
+ sizeStr, isSize := node.attributes[bufferedSizeAttr]
+ if !isSize {
+ return nil, newMissingArgumentError(node.name, bufferedSizeAttr)
+ }
+
+ size, err := strconv.Atoi(sizeStr)
+ if err != nil {
+ return nil, err
+ }
+
+ flushPeriod := 0
+ flushPeriodStr, isFlushPeriod := node.attributes[bufferedFlushPeriodAttr]
+ if isFlushPeriod {
+ flushPeriod, err = strconv.Atoi(flushPeriodStr)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ // Inner writer couldn't have its own format, so we pass 'currentFormat' as its parent format
+ receivers, err := createInnerReceivers(node, currentFormat, formats, cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ formattedWriter, ok := receivers[0].(*formattedWriter)
+ if !ok {
+ return nil, errors.New("buffered writer's child is not writer")
+ }
+
+ // ... and then we check that it hasn't changed
+ if formattedWriter.Format() != currentFormat {
+ return nil, errors.New("inner writer cannot have his own format")
+ }
+
+ bufferedWriter, err := NewBufferedWriter(formattedWriter.Writer(), size, time.Duration(flushPeriod))
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFormattedWriter(bufferedWriter, currentFormat)
+}
+
+// Returns an error if node has any attributes not listed in expectedAttrs.
+func checkUnexpectedAttribute(node *xmlNode, expectedAttrs ...string) error {
+ for attr := range node.attributes {
+ isExpected := false
+ for _, expected := range expectedAttrs {
+ if attr == expected {
+ isExpected = true
+ break
+ }
+ }
+ if !isExpected {
+ return newUnexpectedAttributeError(node.name, attr)
+ }
+ }
+
+ return nil
+}
+
+type expectedElementInfo struct {
+ name string
+ mandatory bool
+ multiple bool
+}
+
+func optionalElement(name string) expectedElementInfo {
+ return expectedElementInfo{name, false, false}
+}
+func mandatoryElement(name string) expectedElementInfo {
+ return expectedElementInfo{name, true, false}
+}
+func multipleElements(name string) expectedElementInfo {
+ return expectedElementInfo{name, false, true}
+}
+func multipleMandatoryElements(name string) expectedElementInfo {
+ return expectedElementInfo{name, true, true}
+}
+
+func checkExpectedElements(node *xmlNode, elements ...expectedElementInfo) error {
+ for _, element := range elements {
+ count := 0
+ for _, child := range node.children {
+ if child.name == element.name {
+ count++
+ }
+ }
+
+ if count == 0 && element.mandatory {
+ return errors.New(node.name + " does not have mandatory subnode - " + element.name)
+ }
+ if count > 1 && !element.multiple {
+ return errors.New(node.name + " has more then one subnode - " + element.name)
+ }
+ }
+
+ for _, child := range node.children {
+ isExpected := false
+ for _, element := range elements {
+ if child.name == element.name {
+ isExpected = true
+ }
+ }
+
+ if !isExpected {
+ return errors.New(node.name + " has unexpected child: " + child.name)
+ }
+ }
+
+ return nil
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser_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/cfg_parser_test.go b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser_test.go
new file mode 100644
index 0000000..7ca0b65
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/cfg_parser_test.go
@@ -0,0 +1,1150 @@
+// 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"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+type customTestReceiverOutput struct {
+ initCalled bool
+ dataPassed string
+ messageOutput string
+ levelOutput LogLevel
+ closed bool
+ flushed bool
+}
+type customTestReceiver struct{ co *customTestReceiverOutput }
+
+func (cr *customTestReceiver) ReceiveMessage(message string, level LogLevel, context LogContextInterface) error {
+ cr.co.messageOutput = message
+ cr.co.levelOutput = level
+ return nil
+}
+
+func (cr *customTestReceiver) String() string {
+ return fmt.Sprintf("custom data='%s'", cr.co.dataPassed)
+}
+
+func (cr *customTestReceiver) AfterParse(initArgs CustomReceiverInitArgs) error {
+ cr.co = new(customTestReceiverOutput)
+ cr.co.initCalled = true
+ cr.co.dataPassed = initArgs.XmlCustomAttrs["test"]
+ return nil
+}
+
+func (cr *customTestReceiver) Flush() {
+ cr.co.flushed = true
+}
+
+func (cr *customTestReceiver) Close() error {
+ cr.co.closed = true
+ return nil
+}
+
+var re = regexp.MustCompile(`[^a-zA-Z0-9]+`)
+
+func getTestFileName(testName, postfix string) string {
+ if len(postfix) != 0 {
+ return strings.ToLower(re.ReplaceAllString(testName, "_")) + "_" + postfix + "_test.log"
+ }
+ return strings.ToLower(re.ReplaceAllString(testName, "_")) + "_test.log"
+}
+
+var parserTests []parserTest
+
+type parserTest struct {
+ testName string
+ config string
+ expected *configForParsing //interface{}
+ errorExpected bool
+ parserConfig *CfgParseParams
+}
+
+func getParserTests() []parserTest {
+ if parserTests == nil {
+ parserTests = make([]parserTest, 0)
+
+ testName := "Simple file output"
+ testLogFileName := getTestFileName(testName, "")
+ testConfig := `
+ <seelog>
+ <outputs>
+ <file path="` + testLogFileName + `"/>
+ </outputs>
+ </seelog>
+ `
+ testExpected := new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ := NewFileWriter(testLogFileName)
+ testHeadSplitter, _ := NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Filter dispatcher"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <filter levels="debug, info, critical">
+ <file path="` + testLogFileName + `"/>
+ </filter>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFilter, _ := NewFilterDispatcher(DefaultFormatter, []interface{}{testfileWriter}, DebugLvl, InfoLvl, CriticalLvl)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testFilter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Console writer"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <console />
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ := NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "SMTP writer"
+ testConfig = `
+<seelog>
+ <outputs>
+ <smtp senderaddress="sa" sendername="sn" hostname="hn" hostport="123" username="un" password="up">
+ <recipient address="ra1"/>
+ <recipient address="ra2"/>
+ <recipient address="ra3"/>
+ <cacertdirpath path="cacdp1"/>
+ <cacertdirpath path="cacdp2"/>
+ </smtp>
+ </outputs>
+</seelog>
+ `
+
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testSMTPWriter := NewSMTPWriter(
+ "sa",
+ "sn",
+ []string{"ra1", "ra2", "ra3"},
+ "hn",
+ "123",
+ "un",
+ "up",
+ []string{"cacdp1", "cacdp2"},
+ DefaultSubjectPhrase,
+ nil,
+ )
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testSMTPWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "SMTP writer custom header and subject configuration"
+ testConfig = `
+<seelog>
+ <outputs>
+ <smtp senderaddress="sa" sendername="sn" hostname="hn" hostport="123" username="un" password="up" subject="ohlala">
+ <recipient address="ra1"/>
+ <cacertdirpath path="cacdp1"/>
+ <header name="Priority" value="Urgent" />
+ <header name="Importance" value="high" />
+ <header name="Sensitivity" value="Company-Confidential" />
+ <header name="Auto-Submitted" value="auto-generated" />
+ </smtp>
+ </outputs>
+</seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testSMTPWriter = NewSMTPWriter(
+ "sa",
+ "sn",
+ []string{"ra1"},
+ "hn",
+ "123",
+ "un",
+ "up",
+ []string{"cacdp1"},
+ "ohlala",
+ []string{"Priority: Urgent", "Importance: high", "Sensitivity: Company-Confidential", "Auto-Submitted: auto-generated"},
+ )
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testSMTPWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Default output"
+ testConfig = `
+ <seelog type="sync"/>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Asyncloop behavior"
+ testConfig = `
+ <seelog type="asyncloop"/>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Asynctimer behavior"
+ testConfig = `
+ <seelog type="asynctimer" asyncinterval="101"/>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncTimerloggerTypeFromString
+ testExpected.LoggerData = asyncTimerLoggerData{101}
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer size"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" />
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ := NewRollingFileWriterSize(testLogFileName, rollingArchiveNone, "", 100, 5, rollingNameModePostfix, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive gzip"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="gzip"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveGzip, "log.tar.gz", 100, 5, rollingNameModePostfix, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="zip"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "log.zip", 100, 5, rollingNameModePostfix, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip with specified path"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile namemode="prefix" type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="zip" archivepath="test.zip"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "test.zip", 100, 5, rollingNameModePrefix, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip exploded"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="zip" archiveexploded="true"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "old", 100, 5, rollingNameModePostfix, true)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive zip exploded with specified path"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile namemode="prefix" type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="zip" archiveexploded="true" archivepath="test_old_logs"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveZip, "test_old_logs", 100, 5, rollingNameModePrefix, true)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer archive none"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile namemode="postfix" type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="none"/>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriter, _ = NewRollingFileWriterSize(testLogFileName, rollingArchiveNone, "", 100, 5, rollingNameModePostfix, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Rolling file writer date"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="date" filename="` + testLogFileName + `" datepattern="2006-01-02T15:04:05Z07:00" />
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ := NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingNameModePostfix, false, false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testrollingFileWriterTime})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Buffered writer"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <buffered size="100500" flushperiod="100">
+ <rollingfile type="date" filename="` + testLogFileName + `" datepattern="2006-01-02T15:04:05Z07:00" />
+ </buffered>
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ = NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingNameModePostfix, false, false)
+ testbufferedWriter, _ := NewBufferedWriter(testrollingFileWriterTime, 100500, 100)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testbufferedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Inner splitter output"
+ testLogFileName1 := getTestFileName(testName, "1")
+ testLogFileName2 := getTestFileName(testName, "2")
+ testLogFileName3 := getTestFileName(testName, "3")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <file path="` + testLogFileName1 + `"/>
+ <splitter>
+ <file path="` + testLogFileName2 + `"/>
+ <file path="` + testLogFileName3 + `"/>
+ </splitter>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter1, _ := NewFileWriter(testLogFileName2)
+ testfileWriter2, _ := NewFileWriter(testLogFileName3)
+ testInnerSplitter, _ := NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter1, testfileWriter2})
+ testfileWriter, _ = NewFileWriter(testLogFileName1)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testfileWriter, testInnerSplitter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ RegisterReceiver("custom-name-1", &customTestReceiver{})
+
+ testName = "Custom receiver 1"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <custom name="custom-name-1" data-test="set"/>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testCustomReceiver, _ := NewCustomReceiverDispatcher(DefaultFormatter, "custom-name-1", CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set",
+ },
+ })
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Custom receiver 2"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <custom name="custom-name-2" data-test="set2"/>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ crec := &customTestReceiver{}
+ cargs := CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set2",
+ },
+ }
+ crec.AfterParse(cargs)
+ testCustomReceiver2, _ := NewCustomReceiverDispatcherByValue(DefaultFormatter, crec, "custom-name-2", cargs)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver2})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ fnc := func(initArgs CustomReceiverInitArgs) (CustomReceiver, error) {
+ return &customTestReceiver{}, nil
+ }
+ cfg := CfgParseParams{
+ CustomReceiverProducers: map[string]CustomReceiverProducer{
+ "custom-name-2": CustomReceiverProducer(fnc),
+ },
+ }
+ testExpected.Params = &cfg
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, &cfg})
+
+ RegisterReceiver("-", &customTestReceiver{})
+ testName = "Custom receiver 3"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <custom name="-" data-test="set3"/>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ creccustom := &customTestReceiver{}
+ cargs3 := CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": "set3",
+ },
+ }
+ creccustom.AfterParse(cargs3)
+ testCustomReceiver, _ = NewCustomReceiverDispatcherByValue(DefaultFormatter, creccustom, "-", cargs3)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceiver})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Custom receivers with formats"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <custom name="custom-name-1" data-test="set1"/>
+ <custom name="custom-name-1" data-test="set2"/>
+ <custom name="custom-name-1" data-test="set3"/>
+ </outputs>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testCustomReceivers := make([]*customReceiverDispatcher, 3)
+ for i := 0; i < 3; i++ {
+ testCustomReceivers[i], _ = NewCustomReceiverDispatcher(DefaultFormatter, "custom-name-1", CustomReceiverInitArgs{
+ XmlCustomAttrs: map[string]string{
+ "test": fmt.Sprintf("set%d", i+1),
+ },
+ })
+ }
+
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testCustomReceivers[0], testCustomReceivers[1], testCustomReceivers[2]})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Format"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs formatid="dateFormat">
+ <file path="` + testLogFileName + `"/>
+ </outputs>
+ <formats>
+ <format id="dateFormat" format="%Level %Msg %File" />
+ </formats>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFormat, _ := NewFormatter("%Level %Msg %File")
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testfileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Format2"
+ testLogFileName = getTestFileName(testName, "")
+ testLogFileName1 = getTestFileName(testName, "1")
+ testConfig = `
+ <seelog type="sync">
+ <outputs formatid="format1">
+ <file path="` + testLogFileName + `"/>
+ <file formatid="format2" path="` + testLogFileName1 + `"/>
+ </outputs>
+ <formats>
+ <format id="format1" format="%Level %Msg %File" />
+ <format id="format2" format="%l %Msg" />
+ </formats>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testfileWriter1, _ = NewFileWriter(testLogFileName1)
+ testFormat1, _ := NewFormatter("%Level %Msg %File")
+ testFormat2, _ := NewFormatter("%l %Msg")
+ formattedWriter, _ := NewFormattedWriter(testfileWriter1, testFormat2)
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat1, []interface{}{testfileWriter, formattedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Minlevel = warn"
+ testConfig = `<seelog minlevel="warn"/>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(WarnLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Maxlevel = trace"
+ testConfig = `<seelog maxlevel="trace"/>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, TraceLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Level between info and error"
+ testConfig = `<seelog minlevel="info" maxlevel="error"/>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(InfoLvl, ErrorLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Off with minlevel"
+ testConfig = `<seelog minlevel="off"/>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewOffConstraints()
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Off with levels"
+ testConfig = `<seelog levels="off"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Levels list"
+ testConfig = `<seelog levels="debug, info, critical"/>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewListConstraints([]LogLevel{
+ DebugLvl, InfoLvl, CriticalLvl})
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = asyncLooploggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Errors #1"
+ testConfig = `<seelog minlevel="debug" minlevel="trace"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #2"
+ testConfig = `<seelog minlevel="error" maxlevel="debug"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #3"
+ testConfig = `<seelog maxlevel="debug" maxlevel="trace"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #4"
+ testConfig = `<seelog maxlevel="off"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #5"
+ testConfig = `<seelog minlevel="off" maxlevel="trace"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #6"
+ testConfig = `<seelog minlevel="warn" maxlevel="error" levels="debug"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #7"
+ testConfig = `<not_seelog/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #8"
+ testConfig = `<seelog levels="warn, debug, test"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #9"
+ testConfig = `<seelog levels=""/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #10"
+ testConfig = `<seelog levels="off" something="abc"/>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #11"
+ testConfig = `<seelog><output/></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #12"
+ testConfig = `<seelog><outputs/><outputs/></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #13"
+ testConfig = `<seelog><exceptions/></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #14"
+ testConfig = `<seelog><formats/></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #15"
+ testConfig = `<seelog><outputs><splitter/></outputs></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #16"
+ testConfig = `<seelog><outputs><filter/></outputs></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #17"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `<seelog><outputs><file path="` + testLogFileName + `"><something/></file></outputs></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #18"
+ testConfig = `<seelog><outputs><buffered size="100500" flushperiod="100"/></outputs></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #19"
+ testConfig = `<seelog><outputs></outputs></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Exceptions: restricting"
+ testConfig =
+ `
+ <seelog type="sync">
+ <exceptions>
+ <exception funcpattern="Test*" filepattern="someFile.go" minlevel="off"/>
+ </exceptions>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ listConstraint, _ := NewOffConstraints()
+ exception, _ := NewLogLevelException("Test*", "someFile.go", listConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Exceptions: allowing #1"
+ testConfig =
+ `
+ <seelog type="sync" levels="error">
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="trace"/>
+ </exceptions>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewListConstraints([]LogLevel{ErrorLvl})
+ minMaxConstraint, _ := NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ exception, _ = NewLogLevelException("*", "testfile.go", minMaxConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Exceptions: allowing #2"
+ testConfig = `
+ <seelog type="sync" levels="off">
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="warn"/>
+ </exceptions>
+ </seelog>
+ `
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewOffConstraints()
+ minMaxConstraint, _ = NewMinMaxConstraints(WarnLvl, CriticalLvl)
+ exception, _ = NewLogLevelException("*", "testfile.go", minMaxConstraint)
+ testExpected.Exceptions = []*LogLevelException{exception}
+ testconsoleWriter, _ = NewConsoleWriter()
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Predefined formats"
+ formatID := predefinedPrefix + "xml-debug-short"
+ testConfig = `
+ <seelog type="sync">
+ <outputs formatid="` + formatID + `">
+ <console />
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testconsoleWriter, _ = NewConsoleWriter()
+ testFormat, _ = predefinedFormats[formatID]
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testconsoleWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Predefined formats redefine"
+ testLogFileName = getTestFileName(testName, "")
+ formatID = predefinedPrefix + "xml-debug-short"
+ testConfig = `
+ <seelog type="sync">
+ <outputs formatid="` + formatID + `">
+ <file path="` + testLogFileName + `"/>
+ </outputs>
+ <formats>
+ <format id="` + formatID + `" format="%Level %Msg %File" />
+ </formats>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testfileWriter, _ = NewFileWriter(testLogFileName)
+ testFormat, _ = NewFormatter("%Level %Msg %File")
+ testHeadSplitter, _ = NewSplitDispatcher(testFormat, []interface{}{testfileWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Conn writer 1"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <conn net="tcp" addr=":8888" />
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testConnWriter := NewConnWriter("tcp", ":8888", false)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testConnWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Conn writer 2"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <conn net="tcp" addr=":8888" reconnectonmsg="true" />
+ </outputs>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testConnWriter = NewConnWriter("tcp", ":8888", true)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{testConnWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ testName = "Errors #11"
+ testConfig = `
+ <seelog type="sync"><exceptions>
+ <exception filepattern="testfile.go" minlevel="trace"/>
+ <exception filepattern="testfile.go" minlevel="warn"/>
+ </exceptions></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #12"
+ testConfig = `
+ <seelog type="sync"><exceptions>
+ <exception filepattern="!@+$)!!%&@(^$" minlevel="trace"/>
+ </exceptions></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #13"
+ testConfig = `
+ <seelog type="sync"><exceptions>
+ <exception filepattern="*" minlevel="unknown"/>
+ </exceptions></seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #14"
+ testConfig = `
+ <seelog type="sync" levels=\u201doff\u201d>
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="off"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #15"
+ testConfig = `
+ <seelog type="sync" levels=\u201dtrace\u201d>
+ <exceptions>
+ <exception filepattern="testfile.go" levels="trace"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #16"
+ testConfig = `
+ <seelog type="sync" minlevel=\u201dtrace\u201d>
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="trace"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #17"
+ testConfig = `
+ <seelog type="sync" minlevel=\u201dtrace\u201d>
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="warn"/>
+ </exceptions>
+ <exceptions>
+ <exception filepattern="testfile.go" minlevel="warn"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #18"
+ testConfig = `
+ <seelog type="sync" minlevel=\u201dtrace\u201d>
+ <exceptions>
+ <exception filepattern="testfile.go"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #19"
+ testConfig = `
+ <seelog type="sync" minlevel=\u201dtrace\u201d>
+ <exceptions>
+ <exception minlevel="warn"/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #20"
+ testConfig = `
+ <seelog type="sync" minlevel=\u201dtrace\u201d>
+ <exceptions>
+ <exception/>
+ </exceptions>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #21"
+ testConfig = `
+ <seelog>
+ <outputs>
+ <splitter>
+ </splitter>
+ </outputs>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #22"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <filter levels="debug, info, critical">
+
+ </filter>
+ </outputs>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #23"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <buffered size="100500" flushperiod="100">
+
+ </buffered>
+ </outputs>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #24"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <buffered size="100500" flushperiod="100">
+ <rollingfile type="date" filename="` + testLogFileName + `" datepattern="2006-01-02T15:04:05Z07:00" formatid="testFormat"/>
+ </buffered>
+ </outputs>
+ <formats>
+ <format id="testFormat" format="%Level %Msg %File 123" />
+ </formats>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #25"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <outputs>
+ <file path="` + testLogFileName + `"/>
+ </outputs>
+ <outputs>
+ <file path="` + testLogFileName + `"/>
+ </outputs>
+ </outputs>
+ </seelog>
+ `
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #26"
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <conn net="tcp" addr=":8888" reconnectonmsg="true1" />
+ </outputs>
+ </seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Errors #27"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <rollingfile type="size" filename="` + testLogFileName + `" maxsize="100" maxrolls="5" archivetype="zip" archivepath="" />
+ </outputs>
+ </seelog>`
+ parserTests = append(parserTests, parserTest{testName, testConfig, nil, true, nil})
+
+ testName = "Buffered writer same formatid override"
+ testLogFileName = getTestFileName(testName, "")
+ testConfig = `
+ <seelog type="sync">
+ <outputs>
+ <buffered size="100500" flushperiod="100" formatid="testFormat">
+ <rollingfile namemode="prefix" type="date" filename="` + testLogFileName + `" datepattern="2006-01-02T15:04:05Z07:00" formatid="testFormat"/>
+ </buffered>
+ </outputs>
+ <formats>
+ <format id="testFormat" format="%Level %Msg %File 123" />
+ </formats>
+ </seelog>`
+ testExpected = new(configForParsing)
+ testExpected.Constraints, _ = NewMinMaxConstraints(TraceLvl, CriticalLvl)
+ testExpected.Exceptions = nil
+ testrollingFileWriterTime, _ = NewRollingFileWriterTime(testLogFileName, rollingArchiveNone, "", 0, "2006-01-02T15:04:05Z07:00", rollingNameModePrefix, false, false)
+ testbufferedWriter, _ = NewBufferedWriter(testrollingFileWriterTime, 100500, 100)
+ testFormat, _ = NewFormatter("%Level %Msg %File 123")
+ formattedWriter, _ = NewFormattedWriter(testbufferedWriter, testFormat)
+ testHeadSplitter, _ = NewSplitDispatcher(DefaultFormatter, []interface{}{formattedWriter})
+ testExpected.LogType = syncloggerTypeFromString
+ testExpected.RootDispatcher = testHeadSplitter
+ parserTests = append(parserTests, parserTest{testName, testConfig, testExpected, false, nil})
+
+ }
+
+ return parserTests
+}
+
+// Temporary solution: compare by string identity. Not the best solution in
+// terms of performance, but a valid one in terms of comparison, because
+// every seelog dispatcher/receiver must have a valid String() func
+// that fully represents its internal parameters.
+func configsAreEqual(conf1 *configForParsing, conf2 interface{}) bool {
+ if conf1 == nil {
+ return conf2 == nil
+ }
+ if conf2 == nil {
+ return conf1 == nil
+ }
+
+ // configForParsing, ok := conf2 //.(*configForParsing)
+ // if !ok {
+ // return false
+ // }
+
+ return fmt.Sprintf("%v", conf1) == fmt.Sprintf("%v", conf2) //configForParsing)
+}
+
+func testLogFileFilter(fn string) bool {
+ return ".log" == filepath.Ext(fn)
+}
+
+func cleanupAfterCfgTest(t *testing.T) {
+ toDel, err := getDirFilePaths(".", testLogFileFilter, true)
+ if nil != err {
+ t.Fatal("Cannot list files in test directory!")
+ }
+
+ for _, p := range toDel {
+ err = tryRemoveFile(p)
+ if nil != err {
+ t.Errorf("cannot remove file %s in test directory: %s", p, err.Error())
+ }
+ }
+}
+
+func parseTest(test parserTest, t *testing.T) {
+ conf, err := configFromReaderWithConfig(strings.NewReader(test.config), test.parserConfig)
+ if /*err != nil &&*/ conf != nil && conf.RootDispatcher != nil {
+ defer func() {
+ if err = conf.RootDispatcher.Close(); err != nil {
+ t.Errorf("\n----ERROR while closing root dispatcher in %s test: %s", test.testName, err)
+ }
+ }()
+ }
+
+ if (err != nil) != test.errorExpected {
+ t.Errorf("\n----ERROR in %s:\nConfig: %s\n* Expected error:%t. Got error: %t\n",
+ test.testName, test.config, test.errorExpected, (err != nil))
+ if err != nil {
+ t.Logf("%s\n", err.Error())
+ }
+ return
+ }
+
+ if err == nil && !configsAreEqual(conf, test.expected) {
+ t.Errorf("\n----ERROR in %s:\nConfig: %s\n* Expected: %v. \n* Got: %v\n",
+ test.testName, test.config, test.expected, conf)
+ }
+}
+
+func TestParser(t *testing.T) {
+ defer cleanupAfterCfgTest(t)
+
+ for _, test := range getParserTests() {
+ parseTest(test, t)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/d969e13b/traffic_stats/vendor/github.com/cihub/seelog/common_closer.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/common_closer.go b/traffic_stats/vendor/github.com/cihub/seelog/common_closer.go
new file mode 100644
index 0000000..1319c22
--- /dev/null
+++ b/traffic_stats/vendor/github.com/cihub/seelog/common_closer.go
@@ -0,0 +1,25 @@
+// 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