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 "fmt" 30 "io" 31) 32 33// A dispatcherInterface is used to dispatch message to all underlying receivers. 34// Dispatch logic depends on given context and log level. Any errors are reported using errorFunc. 35// Also, as underlying receivers may have a state, dispatcher has a ShuttingDown method which performs 36// an immediate cleanup of all data that is stored in the receivers 37type dispatcherInterface interface { 38 flusherInterface 39 io.Closer 40 Dispatch(message string, level LogLevel, context LogContextInterface, errorFunc func(err error)) 41} 42 43type dispatcher struct { 44 formatter *formatter 45 writers []*formattedWriter 46 dispatchers []dispatcherInterface 47} 48 49// Creates a dispatcher which dispatches data to a list of receivers. 50// Each receiver should be either a Dispatcher or io.Writer, otherwise an error will be returned 51func createDispatcher(formatter *formatter, receivers []interface{}) (*dispatcher, error) { 52 if formatter == nil { 53 return nil, errors.New("formatter cannot be nil") 54 } 55 if receivers == nil || len(receivers) == 0 { 56 return nil, errors.New("receivers cannot be nil or empty") 57 } 58 59 disp := &dispatcher{formatter, make([]*formattedWriter, 0), make([]dispatcherInterface, 0)} 60 for _, receiver := range receivers { 61 writer, ok := receiver.(*formattedWriter) 62 if ok { 63 disp.writers = append(disp.writers, writer) 64 continue 65 } 66 67 ioWriter, ok := receiver.(io.Writer) 68 if ok { 69 writer, err := NewFormattedWriter(ioWriter, disp.formatter) 70 if err != nil { 71 return nil, err 72 } 73 disp.writers = append(disp.writers, writer) 74 continue 75 } 76 77 dispInterface, ok := receiver.(dispatcherInterface) 78 if ok { 79 disp.dispatchers = append(disp.dispatchers, dispInterface) 80 continue 81 } 82 83 return nil, errors.New("method can receive either io.Writer or dispatcherInterface") 84 } 85 86 return disp, nil 87} 88 89func (disp *dispatcher) Dispatch( 90 message string, 91 level LogLevel, 92 context LogContextInterface, 93 errorFunc func(err error)) { 94 95 for _, writer := range disp.writers { 96 err := writer.Write(message, level, context) 97 if err != nil { 98 errorFunc(err) 99 } 100 } 101 102 for _, dispInterface := range disp.dispatchers { 103 dispInterface.Dispatch(message, level, context, errorFunc) 104 } 105} 106 107// Flush goes through all underlying writers which implement flusherInterface interface 108// and closes them. Recursively performs the same action for underlying dispatchers 109func (disp *dispatcher) Flush() { 110 for _, disp := range disp.Dispatchers() { 111 disp.Flush() 112 } 113 114 for _, formatWriter := range disp.Writers() { 115 flusher, ok := formatWriter.Writer().(flusherInterface) 116 if ok { 117 flusher.Flush() 118 } 119 } 120} 121 122// Close goes through all underlying writers which implement io.Closer interface 123// and closes them. Recursively performs the same action for underlying dispatchers 124// Before closing, writers are flushed to prevent loss of any buffered data, so 125// a call to Flush() func before Close() is not necessary 126func (disp *dispatcher) Close() error { 127 for _, disp := range disp.Dispatchers() { 128 disp.Flush() 129 err := disp.Close() 130 if err != nil { 131 return err 132 } 133 } 134 135 for _, formatWriter := range disp.Writers() { 136 flusher, ok := formatWriter.Writer().(flusherInterface) 137 if ok { 138 flusher.Flush() 139 } 140 141 closer, ok := formatWriter.Writer().(io.Closer) 142 if ok { 143 err := closer.Close() 144 if err != nil { 145 return err 146 } 147 } 148 } 149 150 return nil 151} 152 153func (disp *dispatcher) Writers() []*formattedWriter { 154 return disp.writers 155} 156 157func (disp *dispatcher) Dispatchers() []dispatcherInterface { 158 return disp.dispatchers 159} 160 161func (disp *dispatcher) String() string { 162 str := "formatter: " + disp.formatter.String() + "\n" 163 164 str += " ->Dispatchers:" 165 166 if len(disp.dispatchers) == 0 { 167 str += "none\n" 168 } else { 169 str += "\n" 170 171 for _, disp := range disp.dispatchers { 172 str += fmt.Sprintf(" ->%s", disp) 173 } 174 } 175 176 str += " ->Writers:" 177 178 if len(disp.writers) == 0 { 179 str += "none\n" 180 } else { 181 str += "\n" 182 183 for _, writer := range disp.writers { 184 str += fmt.Sprintf(" ->%s\n", writer) 185 } 186 } 187 188 return str 189} 190