sys.go 2.9 KB
Newer Older
1
// Copyright 2015 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
5 6 7 8
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 13 14
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
15
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16

17 18 19
package logger

import (
20
	"fmt"
21 22 23
	"sync"
)

24
type stdMsg struct {
Taylor Gerring's avatar
Taylor Gerring committed
25 26 27 28
	level LogLevel
	msg   string
}

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
type jsonMsg []byte

func (m jsonMsg) Level() LogLevel {
	return 0
}

func (m jsonMsg) String() string {
	return string(m)
}

type LogMsg interface {
	Level() LogLevel
	fmt.Stringer
}

func (m stdMsg) Level() LogLevel {
	return m.level
}

func (m stdMsg) String() string {
	return m.msg
}

52
var (
53
	logMessageC = make(chan LogMsg)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	addSystemC  = make(chan LogSystem)
	flushC      = make(chan chan struct{})
	resetC      = make(chan chan struct{})
)

func init() {
	go dispatchLoop()
}

// each system can buffer this many messages before
// blocking incoming log messages.
const sysBufferSize = 500

func dispatchLoop() {
	var (
		systems  []LogSystem
70
		systemIn []chan LogMsg
71 72 73
		systemWG sync.WaitGroup
	)
	bootSystem := func(sys LogSystem) {
74
		in := make(chan LogMsg, sysBufferSize)
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
		systemIn = append(systemIn, in)
		systemWG.Add(1)
		go sysLoop(sys, in, &systemWG)
	}

	for {
		select {
		case msg := <-logMessageC:
			for _, c := range systemIn {
				c <- msg
			}

		case sys := <-addSystemC:
			systems = append(systems, sys)
			bootSystem(sys)

		case waiter := <-resetC:
			// reset means terminate all systems
			for _, c := range systemIn {
				close(c)
			}
			systems = nil
			systemIn = nil
			systemWG.Wait()
			close(waiter)

		case waiter := <-flushC:
			// flush means reboot all systems
			for _, c := range systemIn {
				close(c)
			}
			systemIn = nil
			systemWG.Wait()
			for _, sys := range systems {
				bootSystem(sys)
			}
			close(waiter)
		}
	}
}

116
func sysLoop(sys LogSystem, in <-chan LogMsg, wg *sync.WaitGroup) {
117
	for msg := range in {
118
		sys.LogPrint(msg)
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	}
	wg.Done()
}

// Reset removes all active log systems.
// It blocks until all current messages have been delivered.
func Reset() {
	waiter := make(chan struct{})
	resetC <- waiter
	<-waiter
}

// Flush waits until all current log messages have been dispatched to
// the active log systems.
func Flush() {
	waiter := make(chan struct{})
	flushC <- waiter
	<-waiter
}

// AddLogSystem starts printing messages to the given LogSystem.
func AddLogSystem(sys LogSystem) {
	addSystemC <- sys
}