betterlog 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -0
- data/Dockerfile +46 -0
- data/Gemfile +5 -1
- data/LICENSE +10 -199
- data/Makefile +78 -0
- data/Rakefile +7 -3
- data/TODO.md +1 -0
- data/VERSION +1 -1
- data/betterlog/healthz.go +71 -0
- data/betterlog.gemspec +20 -10
- data/bin/betterlog +176 -175
- data/bin/betterlog_pusher +34 -0
- data/cmd/betterlog-server/LICENSE +13 -0
- data/cmd/betterlog-server/main.go +165 -0
- data/{log.yml → config/log.yml} +5 -35
- data/lib/betterlog/global_metadata.rb +9 -14
- data/lib/betterlog/log/event.rb +135 -133
- data/lib/betterlog/log/event_formatter.rb +99 -97
- data/lib/betterlog/log/severity.rb +38 -36
- data/lib/betterlog/log.rb +163 -146
- data/lib/betterlog/log_event_formatter.rb +41 -39
- data/lib/betterlog/logger.rb +88 -0
- data/lib/betterlog/notifiers.rb +28 -0
- data/lib/betterlog/railtie.rb +8 -0
- data/lib/betterlog/version.rb +1 -1
- data/lib/betterlog.rb +13 -7
- data/spec/betterlog/global_metadata_spec.rb +38 -0
- data/spec/betterlog/log_spec.rb +221 -0
- data/spec/betterlog/logger_spec.rb +65 -0
- data/spec/spec_helper.rb +13 -0
- metadata +82 -28
- data/betterdocs.gemspec +0 -53
- data/lib/betterdocs/version.rb +0 -8
- data/lib/betterlog/betterlog_railtie.rb +0 -5
data/bin/betterlog
CHANGED
@@ -2,239 +2,240 @@
|
|
2
2
|
# vim: set ft=ruby et sw=2 ts=2:
|
3
3
|
|
4
4
|
require 'betterlog'
|
5
|
-
require 'tins/go'
|
6
|
-
require 'file-tail'
|
7
5
|
require 'complex_config/rude'
|
8
6
|
require 'zlib'
|
7
|
+
require 'file/tail'
|
8
|
+
|
9
|
+
module Betterlog
|
10
|
+
class App
|
11
|
+
def initialize(args = ARGV.dup)
|
12
|
+
STDOUT.sync = true
|
13
|
+
@args = args
|
14
|
+
@opts = Tins::GO.go 'cfhp:e:s:S:n:F:', @args, defaults: { ?c => true, ?p => ?d }
|
15
|
+
filter_severities
|
16
|
+
@opts[?h] and usage
|
17
|
+
end
|
9
18
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@args = args
|
14
|
-
@opts = Tins::GO.go 'cfhp:e:s:S:n:F:', @args, defaults: { ?c => true, ?p => ?d }
|
15
|
-
filter_severities
|
16
|
-
@opts[?h] and usage
|
17
|
-
end
|
18
|
-
|
19
|
-
def usage
|
20
|
-
puts <<~end
|
21
|
-
Usage: #{prog} [OPTIONS] [LOGFILES]
|
19
|
+
def usage
|
20
|
+
puts <<~end
|
21
|
+
Usage: #{prog} [OPTIONS] [LOGFILES]
|
22
22
|
|
23
|
-
|
23
|
+
Options are
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
25
|
+
-c to enable colors during pretty printing
|
26
|
+
-f to follow the log files
|
27
|
+
-h to display this help
|
28
|
+
-p FORMAT to pretty print the log file if possible
|
29
|
+
-e EMITTER only output events from these emitters
|
30
|
+
-s MATCH only display events matching this search string
|
31
|
+
-S SEVERITY only output events with severity, e. g. -S '>=warn'
|
32
|
+
-n NUMBER rewind this many lines backwards before tailing log file
|
33
|
+
-F SHORTCUT to open the config files with SHORTCUT
|
34
34
|
|
35
|
-
|
35
|
+
FORMAT values are: #{Array(cc.log.formats?&.attribute_names) * ?,}
|
36
36
|
|
37
|
-
|
37
|
+
SEVERITY values are: #{Log::Severity.all * ?|}
|
38
38
|
|
39
|
-
|
39
|
+
Config file SHORTCUTs are: #{Array(cc.log.config_files?&.attribute_names) * ?,}
|
40
40
|
|
41
|
-
|
41
|
+
Note, that you can use multiple SHORTCUTs via "-F foo -F bar".
|
42
42
|
|
43
|
-
|
43
|
+
Examples:
|
44
44
|
|
45
|
-
|
45
|
+
- Follow rails log in long format with colors for errors or greater:
|
46
46
|
|
47
|
-
|
47
|
+
$ betterlog -f -F rails -p long -c -S ">=error"
|
48
48
|
|
49
|
-
|
50
|
-
|
49
|
+
- Follow rails AND redis logs with default format in colors
|
50
|
+
including the last 10 lines:
|
51
51
|
|
52
|
-
|
52
|
+
$ betterlog -f -F rails -F redis -pd -c -n 10
|
53
53
|
|
54
|
-
|
54
|
+
- Filter stdin from file unicorn.log with default format in color:
|
55
55
|
|
56
|
-
|
56
|
+
$ betterlog -pd -c <unicorn.log
|
57
57
|
|
58
|
-
|
59
|
-
|
58
|
+
- Filter the last 10 lines of file unicorn.log with default format
|
59
|
+
in color:
|
60
60
|
|
61
|
-
|
61
|
+
$ betterlog -c -pd -n 10 unicorn.log
|
62
62
|
|
63
|
-
|
63
|
+
- Filter the last 10 lines of file unicorn.log as JSON events:
|
64
64
|
|
65
|
-
|
65
|
+
$ betterlog -n 10 unicorn.log
|
66
66
|
|
67
|
+
end
|
68
|
+
exit(0)
|
67
69
|
end
|
68
|
-
exit(0)
|
69
|
-
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
71
|
+
private\
|
72
|
+
def filter_severities
|
73
|
+
@severities = Log::Severity.all
|
74
|
+
if severity = @opts[?S]
|
75
|
+
severity.each do |s|
|
76
|
+
if s =~ /\A(>=?|<=?)(.+)/
|
77
|
+
gs = Log::Severity.new($2)
|
78
|
+
@severities.select! { |x| x.send($1, gs) }
|
79
|
+
else
|
80
|
+
gs = Log::Severity.new(s)
|
81
|
+
@severities.select! { |x| x == gs }
|
82
|
+
end
|
82
83
|
end
|
83
84
|
end
|
84
85
|
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def prog
|
88
|
-
File.basename($0)
|
89
|
-
end
|
90
86
|
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def prog
|
88
|
+
File.basename($0)
|
89
|
+
end
|
94
90
|
|
95
|
-
|
96
|
-
|
97
|
-
when /:\?\z/
|
98
|
-
event[$`].present?
|
99
|
-
when /:([^:]+)\z/
|
100
|
-
event[$`].full?(:include?, $1)
|
101
|
-
when String
|
102
|
-
event.to_json.include?(@opts[?s])
|
103
|
-
else
|
104
|
-
return true
|
91
|
+
def emitters
|
92
|
+
Array(@opts[?e])
|
105
93
|
end
|
106
|
-
end
|
107
94
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
95
|
+
def search_matched?(event)
|
96
|
+
case @opts[?s]
|
97
|
+
when /:\?\z/
|
98
|
+
event[$`].present?
|
99
|
+
when /:([^:]+)\z/
|
100
|
+
event[$`].full?(:include?, $1)
|
101
|
+
when String
|
102
|
+
event.to_json.include?(@opts[?s])
|
103
|
+
else
|
104
|
+
return true
|
105
|
+
end
|
116
106
|
end
|
117
|
-
end
|
118
107
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
108
|
+
def output_log_event(prefix, event)
|
109
|
+
return unless @severities.include?(event.severity)
|
110
|
+
return if emitters.full? && !emitters.include?(event.emitter)
|
111
|
+
search_matched?(event) or return
|
112
|
+
if format = @opts[?p]
|
113
|
+
puts event.format(pretty: :format, color: @opts[?c], format: format)
|
114
|
+
else
|
115
|
+
puts "#{prefix}#{event}"
|
124
116
|
end
|
125
|
-
if event = Log::Event.parse(l)
|
126
|
-
filename and event[:file] = filename
|
127
|
-
output_log_event(prefix, event)
|
128
|
-
elsif l =~ /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3})\d* (.*)/
|
129
|
-
event = Log::Event.new(
|
130
|
-
timestamp: $1,
|
131
|
-
message: Term::ANSIColor.uncolor($2),
|
132
|
-
type: 'isoprefix',
|
133
|
-
)
|
134
|
-
filename and event[:file] = filename
|
135
|
-
output_log_event(prefix, event)
|
136
|
-
else
|
137
|
-
@opts[?e] or puts "#{prefix}#{l}"
|
138
117
|
end
|
139
|
-
rescue
|
140
|
-
@opts[?e] or puts "#{prefix}#{l}"
|
141
|
-
end
|
142
118
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
@
|
147
|
-
|
119
|
+
def output_log_line(l, filename)
|
120
|
+
l.blank? and return
|
121
|
+
prefix =
|
122
|
+
if filename && @args.size > 1
|
123
|
+
"#{filename}: "
|
148
124
|
end
|
125
|
+
if event = Log::Event.parse(l)
|
126
|
+
filename and event[:file] = filename
|
127
|
+
output_log_event(prefix, event)
|
128
|
+
elsif l =~ /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3})\d* (.*)/
|
129
|
+
event = Log::Event.new(
|
130
|
+
timestamp: $1,
|
131
|
+
message: Term::ANSIColor.uncolor($2),
|
132
|
+
type: 'isoprefix',
|
133
|
+
)
|
134
|
+
filename and event[:file] = filename
|
135
|
+
output_log_event(prefix, event)
|
149
136
|
else
|
150
|
-
|
151
|
-
end
|
152
|
-
else
|
153
|
-
if @args.empty? and r = cc.log.config_files?&.rails?
|
154
|
-
@args.concat r
|
155
|
-
end
|
156
|
-
if @args.empty?
|
157
|
-
fail "filenames to follow needed"
|
137
|
+
@opts[?e] or puts "#{prefix}#{l}"
|
158
138
|
end
|
139
|
+
rescue
|
140
|
+
@opts[?e] or puts "#{prefix}#{l}"
|
159
141
|
end
|
160
|
-
@args.uniq!
|
161
|
-
end
|
162
142
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
143
|
+
def query_config_file_configuration
|
144
|
+
if @opts[?F]
|
145
|
+
if cfs = cc.log.config_files?
|
146
|
+
@opts[?F].each do |f|
|
147
|
+
@args.concat cfs[f]
|
148
|
+
end
|
149
|
+
else
|
150
|
+
fail "no config files for #{@opts[?F]} defined"
|
151
|
+
end
|
168
152
|
else
|
169
|
-
|
153
|
+
if @args.empty? and r = cc.log.config_files?&.rails?
|
154
|
+
@args.concat r
|
155
|
+
end
|
156
|
+
if @args.empty?
|
157
|
+
fail "filenames to follow needed"
|
158
|
+
end
|
170
159
|
end
|
160
|
+
@args.uniq!
|
171
161
|
end
|
172
|
-
group.each_file { |f| f.max_interval = 1 }
|
173
|
-
t = Thread.new do
|
174
|
-
group.tail { |l| output_log_line(l, l.file.path) }
|
175
|
-
end
|
176
|
-
t.join
|
177
|
-
rescue Interrupt
|
178
|
-
end
|
179
162
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
163
|
+
def follow_files
|
164
|
+
group = File::Tail::Group.new
|
165
|
+
@args.each do |f|
|
166
|
+
if File.exist?(f)
|
167
|
+
group.add_filename f, @opts[?n].to_i
|
168
|
+
else
|
169
|
+
STDERR.puts "file #{f.inspect} does not exist, skip it!"
|
170
|
+
end
|
185
171
|
end
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
172
|
+
group.each_file { |f| f.max_interval = 1 }
|
173
|
+
t = Thread.new do
|
174
|
+
group.tail { |l| output_log_line(l, l.file.path) }
|
175
|
+
end
|
176
|
+
t.join
|
177
|
+
rescue Interrupt
|
178
|
+
end
|
179
|
+
|
180
|
+
def filter_argv
|
181
|
+
for fn in @args
|
182
|
+
unless File.exist?(fn)
|
183
|
+
STDERR.puts "file #{fn.inspect} does not exist, skip it!"
|
184
|
+
next
|
192
185
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
186
|
+
if fn.end_with?('.gz')
|
187
|
+
Zlib::GzipReader.open(fn) do |f|
|
188
|
+
f.extend(File::Tail)
|
189
|
+
f.each_line do |l|
|
190
|
+
output_log_line(l, fn)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
else
|
194
|
+
File::Tail::Logfile.open(fn, backward: @opts[?n].to_i) do |f|
|
195
|
+
f.each_line do |l|
|
196
|
+
output_log_line(l, fn)
|
197
|
+
end
|
197
198
|
end
|
198
199
|
end
|
199
200
|
end
|
200
201
|
end
|
201
|
-
end
|
202
202
|
|
203
|
-
|
204
|
-
|
205
|
-
|
203
|
+
def filter_stdin
|
204
|
+
STDIN.each_line do |l|
|
205
|
+
output_log_line(l, nil)
|
206
|
+
end
|
206
207
|
end
|
207
|
-
end
|
208
208
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
209
|
+
def output_log_sources
|
210
|
+
if @args.empty?
|
211
|
+
STDERR.puts "#{prog} tracking stdin\nseverities: #{@severities * ?|}"
|
212
|
+
else
|
213
|
+
STDERR.puts "#{prog} tracking files:\n"\
|
214
|
+
"#{@args.map { |a| ' ' + a.inspect }.join(' ')}\n"\
|
215
|
+
"severities: #{@severities * ?|}\n"
|
216
|
+
end
|
216
217
|
end
|
217
|
-
end
|
218
218
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
219
|
+
def run
|
220
|
+
if @opts[?f]
|
221
|
+
query_config_file_configuration
|
222
|
+
output_log_sources
|
223
|
+
follow_files
|
224
|
+
elsif @opts[?F] && @args.empty?
|
225
|
+
query_config_file_configuration
|
226
|
+
output_log_sources
|
227
|
+
filter_argv
|
228
|
+
elsif !@args.empty?
|
229
|
+
output_log_sources
|
230
|
+
filter_argv
|
231
|
+
else
|
232
|
+
output_log_sources
|
233
|
+
filter_stdin
|
234
|
+
end
|
234
235
|
end
|
235
236
|
end
|
236
237
|
end
|
237
238
|
|
238
239
|
if File.basename($0) == File.basename(__FILE__)
|
239
|
-
Betterlog.new(ARGV).run
|
240
|
+
Betterlog::App.new(ARGV).run
|
240
241
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set ft=ruby et sw=2 ts=2:
|
3
|
+
|
4
|
+
require 'betterlog'
|
5
|
+
require 'excon'
|
6
|
+
|
7
|
+
lines = Integer(ENV.fetch('BETTERLOG_LINES', 1_000))
|
8
|
+
url = ENV.fetch('BETTERLOG_SERVER_URL')
|
9
|
+
name = ENV['BETTERLOG_NAME']
|
10
|
+
redis = Redis.new(url: ENV.fetch('REDIS_URL'))
|
11
|
+
logger = Betterlog::Logger.new(redis, name: name)
|
12
|
+
|
13
|
+
quit = false
|
14
|
+
|
15
|
+
[ :TERM, :INT, :QUIT ].each { |s| trap(s) { quit = true } }
|
16
|
+
|
17
|
+
STDOUT.sync = true
|
18
|
+
loop do
|
19
|
+
count = 0
|
20
|
+
logger.each_slice(lines).with_index do |batch, i|
|
21
|
+
count.zero? and print ?(
|
22
|
+
count += batch.sum(&:size)
|
23
|
+
attempt(attempts: 10, sleep: -60, reraise: true) do
|
24
|
+
print ?┄
|
25
|
+
Excon.post(url, body: batch.join)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
quit and exit
|
29
|
+
if count.zero?
|
30
|
+
sleep 1
|
31
|
+
else
|
32
|
+
print "→%s)" % Tins::Unit.format(count, format: '%.2f %U', prefix: 1024, unit: ?b)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2018 Florian Frank
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
@@ -0,0 +1,165 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
import (
|
4
|
+
"context"
|
5
|
+
"fmt"
|
6
|
+
"io/ioutil"
|
7
|
+
"log"
|
8
|
+
"net/http"
|
9
|
+
"os"
|
10
|
+
"strings"
|
11
|
+
|
12
|
+
betterlog "github.com/betterplace/betterlog/betterlog"
|
13
|
+
"github.com/go-redis/redis"
|
14
|
+
"github.com/kelseyhightower/envconfig"
|
15
|
+
"github.com/labstack/echo"
|
16
|
+
"github.com/labstack/echo/middleware"
|
17
|
+
"golang.org/x/crypto/acme/autocert"
|
18
|
+
)
|
19
|
+
|
20
|
+
type Config struct {
|
21
|
+
PORT int `default:"5514"`
|
22
|
+
HEALTHZ_PORT int `default:"5513"`
|
23
|
+
HTTP_REALM string `default:"betterlog"`
|
24
|
+
HTTP_AUTH string
|
25
|
+
SSL bool
|
26
|
+
REDIS_PREFIX string
|
27
|
+
REDIS_URL string `default:"redis://localhost:6379"`
|
28
|
+
}
|
29
|
+
|
30
|
+
type RedisCertCache struct {
|
31
|
+
Redis *redis.Client
|
32
|
+
PREFIX string
|
33
|
+
}
|
34
|
+
|
35
|
+
// Get reads certificate data from the specified key name.
|
36
|
+
func (cache RedisCertCache) Get(ctx context.Context, name string) ([]byte, error) {
|
37
|
+
name = strings.Join([]string{cache.PREFIX, name}, "/")
|
38
|
+
done := make(chan struct{})
|
39
|
+
var (
|
40
|
+
err error
|
41
|
+
data string
|
42
|
+
)
|
43
|
+
go func() {
|
44
|
+
defer close(done)
|
45
|
+
result := cache.Redis.Get(name)
|
46
|
+
err = result.Err()
|
47
|
+
if err == nil {
|
48
|
+
data, err = result.Result()
|
49
|
+
}
|
50
|
+
}()
|
51
|
+
select {
|
52
|
+
case <-ctx.Done():
|
53
|
+
return nil, ctx.Err()
|
54
|
+
case <-done:
|
55
|
+
}
|
56
|
+
if err == redis.Nil {
|
57
|
+
return nil, autocert.ErrCacheMiss
|
58
|
+
}
|
59
|
+
return []byte(data), err
|
60
|
+
}
|
61
|
+
|
62
|
+
// Put writes the certificate data to the specified redis key name.
|
63
|
+
func (cache RedisCertCache) Put(ctx context.Context, name string, data []byte) error {
|
64
|
+
name = strings.Join([]string{cache.PREFIX, name}, "/")
|
65
|
+
done := make(chan struct{})
|
66
|
+
var err error
|
67
|
+
go func() {
|
68
|
+
defer close(done)
|
69
|
+
select {
|
70
|
+
case <-ctx.Done():
|
71
|
+
// Don't overwrite the key if the context was canceled.
|
72
|
+
default:
|
73
|
+
result := cache.Redis.Set(name, string(data), 0)
|
74
|
+
err = result.Err()
|
75
|
+
}
|
76
|
+
}()
|
77
|
+
select {
|
78
|
+
case <-ctx.Done():
|
79
|
+
return ctx.Err()
|
80
|
+
case <-done:
|
81
|
+
}
|
82
|
+
return err
|
83
|
+
}
|
84
|
+
|
85
|
+
// Delete removes the specified key name.
|
86
|
+
func (cache RedisCertCache) Delete(ctx context.Context, name string) error {
|
87
|
+
name = strings.Join([]string{cache.PREFIX, name}, "/")
|
88
|
+
var (
|
89
|
+
err error
|
90
|
+
done = make(chan struct{})
|
91
|
+
)
|
92
|
+
go func() {
|
93
|
+
defer close(done)
|
94
|
+
err = cache.Redis.Del(name).Err()
|
95
|
+
}()
|
96
|
+
select {
|
97
|
+
case <-ctx.Done():
|
98
|
+
return ctx.Err()
|
99
|
+
case <-done:
|
100
|
+
}
|
101
|
+
return err
|
102
|
+
}
|
103
|
+
|
104
|
+
func postLogHandler(c echo.Context) error {
|
105
|
+
body := c.Request().Body
|
106
|
+
data, err := ioutil.ReadAll(body)
|
107
|
+
if err == nil {
|
108
|
+
defer body.Close()
|
109
|
+
os.Stdout.Write(data)
|
110
|
+
return c.NoContent(http.StatusOK)
|
111
|
+
} else {
|
112
|
+
return c.String(http.StatusInternalServerError, err.Error())
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
func basicAuthConfig(config Config) middleware.BasicAuthConfig {
|
117
|
+
return middleware.BasicAuthConfig{
|
118
|
+
Realm: config.HTTP_REALM,
|
119
|
+
Validator: func(username, password string, c echo.Context) (bool, error) {
|
120
|
+
httpAuth := strings.Split(config.HTTP_AUTH, ":")
|
121
|
+
if username == httpAuth[0] && password == httpAuth[1] {
|
122
|
+
return true, nil
|
123
|
+
}
|
124
|
+
return false, nil
|
125
|
+
},
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
func initializeRedis(config Config) *redis.Client {
|
130
|
+
options, err := redis.ParseURL(config.REDIS_URL)
|
131
|
+
if err != nil {
|
132
|
+
log.Panic(err)
|
133
|
+
}
|
134
|
+
options.MaxRetries = 3
|
135
|
+
return redis.NewClient(options)
|
136
|
+
}
|
137
|
+
|
138
|
+
func main() {
|
139
|
+
var config Config
|
140
|
+
err := envconfig.Process("", &config)
|
141
|
+
if err != nil {
|
142
|
+
log.Fatal(err)
|
143
|
+
}
|
144
|
+
e := echo.New()
|
145
|
+
if config.HTTP_AUTH != "" {
|
146
|
+
fmt.Println("info: Configuring HTTP Auth access control")
|
147
|
+
e.Use(middleware.BasicAuthWithConfig(basicAuthConfig(config)))
|
148
|
+
}
|
149
|
+
e.POST("/log", postLogHandler)
|
150
|
+
if config.SSL {
|
151
|
+
log.Println("Starting SSL AutoTLS service.")
|
152
|
+
redis := initializeRedis(config)
|
153
|
+
e.AutoTLSManager.Cache = RedisCertCache{
|
154
|
+
Redis: redis,
|
155
|
+
PREFIX: config.REDIS_PREFIX,
|
156
|
+
}
|
157
|
+
go betterlog.StartHealthzEcho(
|
158
|
+
betterlog.Health{
|
159
|
+
PORT: config.HEALTHZ_PORT,
|
160
|
+
})
|
161
|
+
e.Logger.Fatal(e.StartAutoTLS(fmt.Sprintf(":%d", config.PORT)))
|
162
|
+
} else {
|
163
|
+
e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", config.PORT)))
|
164
|
+
}
|
165
|
+
}
|
data/{log.yml → config/log.yml}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
development: &development
|
2
2
|
styles:
|
3
3
|
'timestamp': [ yellow, bold ]
|
4
4
|
'file': [ blue, bold ]
|
@@ -32,9 +32,6 @@ default: &default
|
|
32
32
|
{program}: {message}
|
33
33
|
metric: >
|
34
34
|
{%ft%timestamp} {metric} {value} {type}
|
35
|
-
|
36
|
-
development:
|
37
|
-
<<: *default
|
38
35
|
config_files:
|
39
36
|
rails:
|
40
37
|
- log/development.log
|
@@ -43,35 +40,8 @@ development:
|
|
43
40
|
redis:
|
44
41
|
- /usr/local/var/log/redis.log
|
45
42
|
elasticsearch:
|
46
|
-
- /usr/local/var/log/elasticsearch
|
47
|
-
nginx:
|
48
|
-
- /usr/local/var/log/nginx/access.log
|
49
|
-
- /usr/local/var/log/nginx/error.log
|
50
|
-
legacy_supported: <%= ENV['LOG_LEGACY_SUPPORTED'].to_i == 1 %>
|
51
|
-
|
52
|
-
test:
|
53
|
-
<<: *default
|
54
|
-
config_files:
|
55
|
-
test:
|
56
|
-
- log/test.log
|
57
|
-
legacy_supported: <%= ENV['LOG_LEGACY_SUPPORTED'].to_i == 1 %>
|
58
|
-
|
59
|
-
production:
|
60
|
-
<<: *default
|
61
|
-
config_files:
|
62
|
-
rails:
|
63
|
-
- /var/apps/betterplace/current/log/production.log
|
64
|
-
cron:
|
65
|
-
- /var/apps/betterplace/current/log/cron.log
|
66
|
-
nginx:
|
67
|
-
- /var/apps/betterplace/current/log/nginx.assets.access.log
|
68
|
-
- /var/apps/betterplace/current/log/nginx.assets.error.log
|
69
|
-
- /var/apps/betterplace/current/log/nginx.betterplace.access.log
|
70
|
-
- /var/apps/betterplace/current/log/nginx.betterplace.error.log
|
71
|
-
- /var/apps/betterplace/current/log/nginx.default.access.log
|
72
|
-
- /var/apps/betterplace/current/log/nginx.default.error.log
|
73
|
-
memosig:
|
74
|
-
- /var/log/memosig/current
|
75
|
-
unicorn:
|
76
|
-
- /var/log/unicorn/current
|
43
|
+
- /usr/local/var/log/elasticsearch.log
|
77
44
|
legacy_supported: yes
|
45
|
+
test: *development
|
46
|
+
staging: *development
|
47
|
+
production: *development
|