Skip to content

Commit b077f48

Browse files
authored
Merge pull request #1500 from fuweid/feature_syslog
feature: init syslog functionality in pouchd
2 parents 8284773 + 5d9dc50 commit b077f48

36 files changed

Lines changed: 2075 additions & 34 deletions

apis/opts/log_options.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package opts
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/alibaba/pouch/pkg/utils"
7+
)
8+
9+
// ParseLogOptions parses [key=value] slice-type log options into map.
10+
func ParseLogOptions(driver string, logOpts []string) (map[string]string, error) {
11+
opts, err := utils.ConvertKVStringsToMap(logOpts)
12+
if err != nil {
13+
return nil, err
14+
}
15+
16+
if driver == "none" && len(opts) > 0 {
17+
return nil, fmt.Errorf("don't allow to set logging opts for driver %s", driver)
18+
}
19+
return opts, nil
20+
}

apis/opts/log_options_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package opts
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestParseLogOptions(t *testing.T) {
9+
type tCases struct {
10+
driver string
11+
logOpts []string
12+
13+
hasError bool
14+
expected map[string]string
15+
}
16+
17+
for idx, tc := range []tCases{
18+
{
19+
driver: "",
20+
logOpts: nil,
21+
hasError: false,
22+
expected: map[string]string{},
23+
}, {
24+
driver: "none",
25+
logOpts: nil,
26+
hasError: false,
27+
expected: map[string]string{},
28+
}, {
29+
driver: "none",
30+
logOpts: []string{"haha"},
31+
hasError: true,
32+
expected: nil,
33+
}, {
34+
driver: "none",
35+
logOpts: []string{"test=1"},
36+
hasError: true,
37+
expected: nil,
38+
}, {
39+
driver: "json-file",
40+
logOpts: []string{"test=1"},
41+
hasError: false,
42+
expected: map[string]string{
43+
"test": "1",
44+
},
45+
}, {
46+
driver: "json-file",
47+
logOpts: []string{"test=1=1"},
48+
hasError: false,
49+
expected: map[string]string{
50+
"test": "1=1",
51+
},
52+
}, {
53+
driver: "json-file",
54+
logOpts: []string{"test=1", "flag=oops", "test=2"},
55+
hasError: false,
56+
expected: map[string]string{
57+
"test": "2",
58+
"flag": "oops",
59+
},
60+
},
61+
} {
62+
got, err := ParseLogOptions(tc.driver, tc.logOpts)
63+
if err == nil && tc.hasError {
64+
t.Fatalf("[%d case] should have error here, but got nothing", idx)
65+
}
66+
if err != nil && !tc.hasError {
67+
t.Fatalf("[%d case] should have no error here, but got error(%v)", idx, err)
68+
}
69+
70+
if !reflect.DeepEqual(got, tc.expected) {
71+
t.Fatalf("[%d case] should have (%v), but got (%v)", idx, tc.expected, got)
72+
}
73+
}
74+
}

cli/common_flags.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container {
4242
flagSet.StringVar(&c.ipcMode, "ipc", "", "IPC namespace to use")
4343
flagSet.StringSliceVarP(&c.labels, "label", "l", nil, "Set labels for a container")
4444

45+
// log driver and log options
46+
flagSet.StringVar(&c.logDriver, "log-driver", "json-file", "Logging driver for the container")
47+
flagSet.StringSliceVar(&c.logOpts, "log-opt", nil, "Log driver options")
48+
4549
// memory
4650

4751
flagSet.StringVarP(&c.memory, "memory", "m", "", "Memory limit")

cli/container.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ type container struct {
7272
ulimit Ulimit
7373
pidsLimit int64
7474

75+
// log driver and log option
76+
logDriver string
77+
logOpts []string
78+
7579
//add for rich container mode
7680
rich bool
7781
richMode string
@@ -172,6 +176,11 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {
172176
return nil, err
173177
}
174178

179+
logOpts, err := opts.ParseLogOptions(c.logDriver, c.logOpts)
180+
if err != nil {
181+
return nil, err
182+
}
183+
175184
config := &types.ContainerCreateConfig{
176185
ContainerConfig: types.ContainerConfig{
177186
Tty: c.tty,
@@ -242,6 +251,10 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {
242251
CapDrop: c.capDrop,
243252
PortBindings: portBindings,
244253
OomScoreAdj: c.oomScoreAdj,
254+
LogConfig: &types.LogConfig{
255+
LogDriver: c.logDriver,
256+
LogOpts: logOpts,
257+
},
245258
},
246259

247260
NetworkingConfig: networkingConfig,

daemon/containerio/jsonfile.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ func (jf *jsonFile) Name() string {
3737
}
3838

3939
func (jf *jsonFile) Init(opt *Option) error {
40-
if _, err := os.Stat(opt.rootDir); err != nil {
40+
rootDir := opt.info.ContainerRootDir
41+
if _, err := os.Stat(rootDir); err != nil {
4142
return err
4243
}
4344

44-
logPath := filepath.Join(opt.rootDir, jsonFilePathName)
45+
logPath := filepath.Join(rootDir, jsonFilePathName)
4546
w, err := jsonfile.NewJSONLogFile(logPath, 0644)
4647
if err != nil {
4748
return err

daemon/containerio/options.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import (
66
"os"
77

88
"github.com/alibaba/pouch/cri/stream/remotecommand"
9+
"github.com/alibaba/pouch/daemon/logger"
910
)
1011

1112
// Option is used to pass some data into ContainerIO.
13+
//
14+
// FIXME(fuwei): use logger.Info to separate options and backends.
1215
type Option struct {
16+
info logger.Info
17+
1318
id string
14-
rootDir string
1519
stdin bool
1620
muxDisabled bool
1721
backends map[string]struct{}
@@ -41,10 +45,10 @@ func WithID(id string) func(*Option) {
4145
}
4246
}
4347

44-
// WithRootDir specified the container's root dir.
45-
func WithRootDir(dir string) func(*Option) {
48+
// WithLoggerInfo specified the container's logger information.
49+
func WithLoggerInfo(info logger.Info) func(*Option) {
4650
return func(opt *Option) {
47-
opt.rootDir = dir
51+
opt.info = info
4852
}
4953
}
5054

@@ -82,6 +86,16 @@ func WithJSONFile() func(*Option) {
8286
}
8387
}
8488

89+
// WithSyslog specified the syslog backend.
90+
func WithSyslog() func(*Option) {
91+
return func(opt *Option) {
92+
if opt.backends == nil {
93+
opt.backends = make(map[string]struct{})
94+
}
95+
opt.backends["syslog"] = struct{}{}
96+
}
97+
}
98+
8599
// WithHijack specified the hijack backend.
86100
func WithHijack(hi http.Hijacker, upgrade bool) func(*Option) {
87101
return func(opt *Option) {

daemon/containerio/syslog.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package containerio
2+
3+
import (
4+
"io"
5+
6+
"github.com/alibaba/pouch/daemon/logger"
7+
"github.com/alibaba/pouch/daemon/logger/syslog"
8+
)
9+
10+
func init() {
11+
Register(func() Backend {
12+
return &syslogging{}
13+
})
14+
}
15+
16+
type customWriter struct {
17+
w func(p []byte) (int, error)
18+
}
19+
20+
func (cw *customWriter) Write(p []byte) (int, error) {
21+
return cw.w(p)
22+
}
23+
24+
type syslogging struct {
25+
w *syslog.Syslog
26+
}
27+
28+
func (s *syslogging) Init(opt *Option) error {
29+
w, err := syslog.NewSyslog(opt.info)
30+
if err != nil {
31+
return err
32+
}
33+
s.w = w
34+
return nil
35+
}
36+
37+
func (s *syslogging) Name() string {
38+
return "syslog"
39+
}
40+
41+
func (s *syslogging) In() io.Reader {
42+
return nil
43+
}
44+
45+
func (s *syslogging) Out() io.Writer {
46+
return &customWriter{w: s.sourceWriteFunc("stdout")}
47+
}
48+
49+
func (s *syslogging) Err() io.Writer {
50+
return &customWriter{w: s.sourceWriteFunc("stderr")}
51+
}
52+
53+
func (s *syslogging) Close() error {
54+
return s.w.Close()
55+
}
56+
57+
func (s *syslogging) sourceWriteFunc(source string) func([]byte) (int, error) {
58+
return func(p []byte) (int, error) {
59+
if len(p) == 0 {
60+
return 0, nil
61+
}
62+
63+
msg := &logger.LogMessage{
64+
Source: source,
65+
Line: p,
66+
}
67+
68+
if err := s.w.WriteLogMessage(msg); err != nil {
69+
return 0, err
70+
}
71+
return len(p), nil
72+
}
73+
}

daemon/logger/info.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package logger
2+
3+
import (
4+
"github.com/alibaba/pouch/pkg/utils"
5+
)
6+
7+
// Info provides container information for log driver.
8+
//
9+
// TODO(fuwei): add more fields.
10+
type Info struct {
11+
LogConfig map[string]string
12+
13+
ContainerID string
14+
ContainerName string
15+
ContainerImageID string
16+
ContainerLabels map[string]string
17+
ContainerRootDir string
18+
19+
DaemonName string
20+
}
21+
22+
// ID returns the container truncated ID.
23+
func (i *Info) ID() string {
24+
return utils.TruncateID(i.ContainerID)
25+
}
26+
27+
// FullID returns the container ID.
28+
func (i *Info) FullID() string {
29+
return i.ContainerID
30+
}
31+
32+
// Name returns the container name.
33+
func (i *Info) Name() string {
34+
return i.ContainerName
35+
}
36+
37+
// ImageID returns the container's image truncated ID.
38+
func (i *Info) ImageID() string {
39+
return utils.TruncateID(i.ContainerImageID)
40+
}
41+
42+
// ImageFullID returns the container's image ID.
43+
func (i *Info) ImageFullID() string {
44+
return i.ContainerImageID
45+
}

daemon/logger/loggerutils/tag.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package loggerutils
2+
3+
import (
4+
"bytes"
5+
6+
"github.com/alibaba/pouch/daemon/logger"
7+
"github.com/alibaba/pouch/pkg/utils/templates"
8+
)
9+
10+
// GenerateLogTag returns a tag which can be used for different log drivers
11+
// based on the container.
12+
func GenerateLogTag(info logger.Info, defaultTemplate string) (string, error) {
13+
tagTemplate := info.LogConfig["tag"]
14+
if tagTemplate == "" {
15+
tagTemplate = defaultTemplate
16+
}
17+
18+
tmpl, err := templates.NewParse("logtag", tagTemplate)
19+
if err != nil {
20+
return "", err
21+
}
22+
23+
buf := bytes.Buffer{}
24+
if err := tmpl.Execute(&buf, &info); err != nil {
25+
return "", err
26+
}
27+
return buf.String(), nil
28+
}

0 commit comments

Comments
 (0)