Skip to content

Commit 077dafc

Browse files
authored
Merge pull request #33 from AdoHe/journald
add journal support
2 parents 652ab56 + 86f4d07 commit 077dafc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2677
-3908
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1+
os:
2+
- linux
3+
sudo: required
4+
dist: trusty
15
language: go
26
go:
37
- 1.6
8+
before_install:
9+
- sudo apt-get -qq update
10+
- sudo apt-get install -y libsystemd-journal-dev
411
install:
512
- mkdir -p $HOME/gopath/src/k8s.io
613
- mv $TRAVIS_BUILD_DIR $HOME/gopath/src/k8s.io/node-problem-detector

Godeps/Godeps.json

Lines changed: 32 additions & 54 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/kernelmonitor/kernel_log_watcher.go

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@ limitations under the License.
1717
package kernelmonitor
1818

1919
import (
20+
"bufio"
21+
"bytes"
22+
"fmt"
23+
"io"
2024
"os"
25+
"strings"
2126
"time"
2227

2328
"k8s.io/node-problem-detector/pkg/kernelmonitor/translator"
2429
"k8s.io/node-problem-detector/pkg/kernelmonitor/types"
2530
"k8s.io/node-problem-detector/pkg/kernelmonitor/util"
2631

32+
"github.com/coreos/go-systemd/sdjournal"
2733
"github.com/golang/glog"
28-
"github.com/hpcloud/tail"
34+
"github.com/google/cadvisor/utils/tail"
2935
utilclock "github.com/pivotal-golang/clock"
3036
)
3137

@@ -54,12 +60,12 @@ type KernelLogWatcher interface {
5460

5561
type kernelLogWatcher struct {
5662
// trans is the translator translates the log into internal format.
57-
trans translator.Translator
58-
cfg WatcherConfig
59-
tl *tail.Tail
60-
logCh chan *types.KernelLog
61-
tomb *util.Tomb
62-
clock utilclock.Clock
63+
trans translator.Translator
64+
cfg WatcherConfig
65+
reader *bufio.Reader
66+
logCh chan *types.KernelLog
67+
tomb *util.Tomb
68+
clock utilclock.Clock
6369
}
6470

6571
// NewKernelLogWatcher creates a new kernel log watcher.
@@ -88,25 +94,17 @@ func (k *kernelLogWatcher) Watch() (<-chan *types.KernelLog, error) {
8894
// To avoid this, we decide to add this temporarily hack. When KernelMonitor can't find the kernel
8995
// log file, it will print a log and then return nil channel and no error. Since nil channel will
9096
// always be blocked, the NodeProblemDetector will block forever.
91-
// TODO(random-liu):
92-
// 1. Add journald supports to support GCI.
93-
// 2. Schedule KernelMonitor only on supported node (with node label and selector)
9497
if _, err := os.Stat(path); os.IsNotExist(err) {
9598
glog.Infof("kernel log %q is not found, kernel monitor doesn't support the os distro", path)
9699
return nil, nil
97100
}
98101
// TODO(random-liu): Rate limit tail file.
99-
// TODO(random-liu): Figure out what happens if log lines are removed.
100102
// Notice that, kernel log watcher doesn't look back to the rolled out logs.
101-
var err error
102-
k.tl, err = tail.TailFile(path, tail.Config{
103-
Poll: true,
104-
ReOpen: true,
105-
Follow: true,
106-
})
103+
reader, err := getLogReader(path)
107104
if err != nil {
108105
return nil, err
109106
}
107+
k.reader = bufio.NewReader(reader)
110108
glog.Info("Start watching kernel log")
111109
go k.watchLoop()
112110
return k.logCh, nil
@@ -126,15 +124,35 @@ func (k *kernelLogWatcher) watchLoop() {
126124
if err != nil {
127125
glog.Fatalf("failed to parse duration %q: %v", k.cfg.Lookback, err)
128126
}
127+
var buffer bytes.Buffer
129128
for {
130129
select {
131-
case line := <-k.tl.Lines:
132-
// Notice that tail has trimmed '\n'
133-
if line.Err != nil {
134-
glog.Errorf("Tail error: %v", line.Err)
135-
continue
136-
}
137-
log, err := k.trans.Translate(line.Text)
130+
case <-k.tomb.Stopping():
131+
glog.Infof("Stop watching kernel log")
132+
return
133+
default:
134+
}
135+
136+
line, err := k.reader.ReadString('\n')
137+
if err != nil && err != io.EOF {
138+
glog.Errorf("exiting kernel log watch with error: %v", err)
139+
return
140+
}
141+
if err == io.EOF {
142+
buffer.WriteString(line)
143+
time.Sleep(100 * time.Millisecond)
144+
continue
145+
}
146+
if line == "" {
147+
time.Sleep(100 * time.Millisecond)
148+
continue
149+
}
150+
if err == nil {
151+
buffer.WriteString(line)
152+
// trim `\n`
153+
line = strings.TrimRight(buffer.String(), "\n")
154+
buffer.Reset()
155+
log, err := k.trans.Translate(line)
138156
if err != nil {
139157
glog.Infof("Unable to parse line: %q, %v", line, err)
140158
continue
@@ -144,14 +162,48 @@ func (k *kernelLogWatcher) watchLoop() {
144162
continue
145163
}
146164
k.logCh <- log
147-
case <-k.tomb.Stopping():
148-
k.tl.Stop()
149-
glog.Infof("Stop watching kernel log")
150-
return
151165
}
152166
}
153167
}
154168

169+
// getLogReader gets a kernel log reader.
170+
func getLogReader(path string) (io.Reader, error) {
171+
if len(path) != 0 {
172+
return tryLogFile(path)
173+
}
174+
return tryJournal()
175+
}
176+
177+
func tryJournal() (io.Reader, error) {
178+
r, err := sdjournal.NewJournalReader(sdjournal.JournalReaderConfig{
179+
NumFromTail: uint64(0),
180+
Matches: []sdjournal.Match{
181+
{
182+
Field: sdjournal.SD_JOURNAL_FIELD_TRANSPORT,
183+
Value: "kernel",
184+
},
185+
},
186+
})
187+
if err != nil {
188+
return nil, fmt.Errorf("error opening journal: %v", err)
189+
}
190+
if r == nil {
191+
return nil, fmt.Errorf("got a nil reader")
192+
}
193+
glog.Info("Kernel log watcher use journal")
194+
return r, nil
195+
}
196+
197+
func tryLogFile(path string) (io.Reader, error) {
198+
tail, err := tail.NewTail(path)
199+
if err != nil {
200+
return nil, err
201+
}
202+
glog.Infof("Kernel log watcher use log file: %s", path)
203+
time.Sleep(1000 * time.Millisecond)
204+
return tail, nil
205+
}
206+
155207
func parseDuration(s string) (time.Duration, error) {
156208
// If the duration is not configured, just return 0 by default
157209
if s == "" {

pkg/kernelmonitor/kernel_log_watcher_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package kernelmonitor
1818

1919
import (
2020
"io/ioutil"
21-
"os"
21+
//"os"
2222
"reflect"
2323
"testing"
2424
"time"
@@ -101,12 +101,13 @@ func TestWatch(t *testing.T) {
101101
}
102102
defer func() {
103103
f.Close()
104-
os.Remove(f.Name())
104+
//os.Remove(f.Name())
105105
}()
106106
_, err = f.Write([]byte(test.log))
107107
if err != nil {
108108
t.Fatal(err)
109109
}
110+
110111
w := NewKernelLogWatcher(WatcherConfig{KernelLogPath: f.Name(), Lookback: test.lookback})
111112
// Set the fake clock.
112113
w.(*kernelLogWatcher).clock = fakeClock

0 commit comments

Comments
 (0)