-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
168 lines (140 loc) · 2.93 KB
/
main.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package graphite_log
import (
"fmt"
"io"
"strconv"
"strings"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/marpaia/graphite-golang"
"go.uber.org/zap"
)
func init() {
caddy.RegisterModule(GraphiteLog{})
}
/*
GraphiteLog is a Caddy logger used to send server activity to a Graphite
database.
Templating is available as follow :
.Level
.Date
.Logger
.Msg
.Request
.RemoteIP
.RemotePort
.ClientIP
.Proto
.Method
.Host
.URI
.Headers
.BytesRead
.UserID
.Duration
.Size
.Status
.RespHeaders map[string][]string
.DirName
.FileName
*/
type GraphiteLog struct {
// IP address or host name of the graphite server
Server string `json:"server"`
// Port number to be used (usually 2003)
Port int `json:"port"`
// Metrics Path, can be templated
Path string `json:"path"`
// Value to be sent, can be templated
Value string `json:"value"`
// Methods to be logged
Methods []string `json:"methods"`
logger *zap.Logger
}
func (GraphiteLog) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "caddy.logging.writers.graphite",
New: func() caddy.Module { return new(GraphiteLog) },
}
}
func (l *GraphiteLog) Provision(ctx caddy.Context) error {
l.logger = ctx.Logger() // g.logger is a *zap.Logger
return nil
}
func (l *GraphiteLog) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !d.NextArg() {
return d.ArgErr()
}
for block := d.Nesting(); d.NextBlock(block); {
switch d.Val() {
case "server":
if !d.NextArg() {
return d.ArgErr()
}
l.Server = d.Val()
case "port":
if !d.NextArg() {
return d.ArgErr()
}
p, err := strconv.Atoi(d.Val())
if err != nil {
l.logger.Error(err.Error())
return d.ArgErr()
}
l.Port = p
case "path":
if !d.NextArg() {
return d.ArgErr()
}
l.Path = d.Val()
case "value":
if !d.NextArg() {
return d.ArgErr()
}
l.Value = d.Val()
case "methods":
for d.NextArg() {
l.Methods = append(l.Methods, d.Val())
}
}
}
return nil
}
func (l *GraphiteLog) Validate() error {
if l.Server == "" {
return fmt.Errorf("No Server Set")
}
if l.Port == 0 {
l.Port = 2003
}
if l.Path == "" {
return fmt.Errorf("No Path Set")
}
if l.Value == "" {
l.Value = "1"
}
return nil
}
func (g *GraphiteLog) String() string {
return "graphite"
}
func (g *GraphiteLog) WriterKey() string {
return fmt.Sprintf("graphite_log_%s_%d_%s_%s_%s", g.Server, g.Port, g.Path, g.Value, strings.Join(g.Methods, ","))
}
func (l *GraphiteLog) OpenWriter() (io.WriteCloser, error) {
// Open connection to Graphite server
graphite, err := graphite.NewGraphite(l.Server, l.Port)
if err != nil {
l.logger.Error(err.Error())
}
return &GraphiteWriter{
GraphiteLog: l,
Graphite: graphite,
}, nil
}
// Interface guards
var (
_ caddy.Provisioner = (*GraphiteLog)(nil)
_ caddy.WriterOpener = (*GraphiteLog)(nil)
_ caddyfile.Unmarshaler = (*GraphiteLog)(nil)
)