forked from lomik/zapwriter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoutput.go
128 lines (107 loc) · 2.05 KB
/
output.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
116
117
118
119
120
121
122
123
124
125
126
127
128
package zapwriter
import (
"fmt"
"io"
"log"
"net/url"
"os"
"sync"
)
type WriteSyncer interface {
io.Writer
Sync() error
}
type closeable interface {
Close() (err error)
}
type Output interface {
io.Writer
Sync() error
}
var knownSchemes = make(map[string](func(string) (Output, error)))
var knownSchemesMutex sync.RWMutex
func RegisterScheme(scheme string, constructor func(path string) (Output, error)) {
knownSchemesMutex.Lock()
if _, exists := knownSchemes[scheme]; exists {
log.Fatalf("scheme %#v already registered", scheme)
}
knownSchemes[scheme] = constructor
knownSchemesMutex.Unlock()
}
type output struct {
sync.RWMutex
out WriteSyncer
closeable bool
dsn string
}
func New(dsn string) (Output, error) {
o := &output{}
err := o.apply(dsn)
if err != nil {
return nil, err
}
return o, err
}
func (o *output) apply(dsn string) error {
if dsn == o.dsn && o.out != nil { // nothing changed
return nil
}
var newOut WriteSyncer
var newCloseable bool
u, err := url.Parse(dsn)
if err != nil {
return err
}
if u.Path == "" || u.Path == "stderr" {
newOut = os.Stderr
} else if u.Path == "stdout" {
newOut = os.Stdout
} else {
if u.Scheme == "" || u.Scheme == "file" {
newOut, err = File(u.Path)
if err != nil {
return err
}
newCloseable = true
} else {
knownSchemesMutex.RLock()
newFunc, exists := knownSchemes[u.Scheme]
knownSchemesMutex.RUnlock()
if !exists {
return fmt.Errorf("unknown scheme %#v", u.Scheme)
}
newOut, err = newFunc(u.String())
if err != nil {
return err
}
if _, ok := newOut.(closeable); ok {
newCloseable = true
}
}
}
if o.out != nil && o.closeable {
if c, ok := o.out.(closeable); ok {
c.Close()
}
o.out = nil
}
o.out = newOut
o.closeable = newCloseable
return nil
}
func (o *output) Sync() (err error) {
o.RLock()
if o.out != nil {
err = o.out.Sync()
}
o.RUnlock()
return
}
func (o *output) Write(p []byte) (n int, err error) {
o.RLock()
if o.out != nil {
n, err = o.out.Write(p)
}
o.RUnlock()
return
}