1// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this
9//    list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright notice,
11//    this list of conditions and the following disclaimer in the documentation
12//    and/or other materials provided with the distribution.
13//
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25package seelog
26
27import (
28	"errors"
29)
30
31type loggerTypeFromString uint8
32
33const (
34	syncloggerTypeFromString = iota
35	asyncLooploggerTypeFromString
36	asyncTimerloggerTypeFromString
37	adaptiveLoggerTypeFromString
38	defaultloggerTypeFromString = asyncLooploggerTypeFromString
39)
40
41const (
42	syncloggerTypeFromStringStr       = "sync"
43	asyncloggerTypeFromStringStr      = "asyncloop"
44	asyncTimerloggerTypeFromStringStr = "asynctimer"
45	adaptiveLoggerTypeFromStringStr   = "adaptive"
46)
47
48// asyncTimerLoggerData represents specific data for async timer logger
49type asyncTimerLoggerData struct {
50	AsyncInterval uint32
51}
52
53// adaptiveLoggerData represents specific data for adaptive timer logger
54type adaptiveLoggerData struct {
55	MinInterval      uint32
56	MaxInterval      uint32
57	CriticalMsgCount uint32
58}
59
60var loggerTypeToStringRepresentations = map[loggerTypeFromString]string{
61	syncloggerTypeFromString:       syncloggerTypeFromStringStr,
62	asyncLooploggerTypeFromString:  asyncloggerTypeFromStringStr,
63	asyncTimerloggerTypeFromString: asyncTimerloggerTypeFromStringStr,
64	adaptiveLoggerTypeFromString:   adaptiveLoggerTypeFromStringStr,
65}
66
67// getLoggerTypeFromString parses a string and returns a corresponding logger type, if successful.
68func getLoggerTypeFromString(logTypeString string) (level loggerTypeFromString, found bool) {
69	for logType, logTypeStr := range loggerTypeToStringRepresentations {
70		if logTypeStr == logTypeString {
71			return logType, true
72		}
73	}
74
75	return 0, false
76}
77
78// logConfig stores logging configuration. Contains messages dispatcher, allowed log level rules
79// (general constraints and exceptions)
80type logConfig struct {
81	Constraints    logLevelConstraints  // General log level rules (>min and <max, or set of allowed levels)
82	Exceptions     []*LogLevelException // Exceptions to general rules for specific files or funcs
83	RootDispatcher dispatcherInterface  // Root of output tree
84}
85
86func NewLoggerConfig(c logLevelConstraints, e []*LogLevelException, d dispatcherInterface) *logConfig {
87	return &logConfig{c, e, d}
88}
89
90// configForParsing is used when parsing config from file: logger type is deduced from string, params
91// need to be converted from attributes to values and passed to specific logger constructor. Also,
92// custom registered receivers and other parse params are used in this case.
93type configForParsing struct {
94	logConfig
95	LogType    loggerTypeFromString
96	LoggerData interface{}
97	Params     *CfgParseParams // Check cfg_parser: CfgParseParams
98}
99
100func newFullLoggerConfig(
101	constraints logLevelConstraints,
102	exceptions []*LogLevelException,
103	rootDispatcher dispatcherInterface,
104	logType loggerTypeFromString,
105	logData interface{},
106	cfgParams *CfgParseParams) (*configForParsing, error) {
107	if constraints == nil {
108		return nil, errors.New("constraints can not be nil")
109	}
110	if rootDispatcher == nil {
111		return nil, errors.New("rootDispatcher can not be nil")
112	}
113
114	config := new(configForParsing)
115	config.Constraints = constraints
116	config.Exceptions = exceptions
117	config.RootDispatcher = rootDispatcher
118	config.LogType = logType
119	config.LoggerData = logData
120	config.Params = cfgParams
121
122	return config, nil
123}
124
125// IsAllowed returns true if logging with specified log level is allowed in current context.
126// If any of exception patterns match current context, then exception constraints are applied. Otherwise,
127// the general constraints are used.
128func (config *logConfig) IsAllowed(level LogLevel, context LogContextInterface) bool {
129	allowed := config.Constraints.IsAllowed(level) // General rule
130
131	// Exceptions:
132	if context.IsValid() {
133		for _, exception := range config.Exceptions {
134			if exception.MatchesContext(context) {
135				return exception.IsAllowed(level)
136			}
137		}
138	}
139
140	return allowed
141}
142