Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apis/opts/log_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package opts

import (
"fmt"

"github.com/alibaba/pouch/pkg/utils"
)

// ParseLogOptions parses [key=value] slice-type log options into map.
func ParseLogOptions(driver string, logOpts []string) (map[string]string, error) {
opts, err := utils.ConvertKVStringsToMap(logOpts)
if err != nil {
return nil, err
}

if driver == "none" && len(opts) > 0 {
return nil, fmt.Errorf("don't allow to set logging opts for driver %s", driver)
}
return opts, nil
}
74 changes: 74 additions & 0 deletions apis/opts/log_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package opts

import (
"reflect"
"testing"
)

func TestParseLogOptions(t *testing.T) {
type tCases struct {
driver string
logOpts []string

hasError bool
expected map[string]string
}

for idx, tc := range []tCases{
{
driver: "",
logOpts: nil,
hasError: false,
expected: map[string]string{},
}, {
driver: "none",
logOpts: nil,
hasError: false,
expected: map[string]string{},
}, {
driver: "none",
logOpts: []string{"haha"},
hasError: true,
expected: nil,
}, {
driver: "none",
logOpts: []string{"test=1"},
hasError: true,
expected: nil,
}, {
driver: "json-file",
logOpts: []string{"test=1"},
hasError: false,
expected: map[string]string{
"test": "1",
},
}, {
driver: "json-file",
logOpts: []string{"test=1=1"},
hasError: false,
expected: map[string]string{
"test": "1=1",
},
}, {
driver: "json-file",
logOpts: []string{"test=1", "flag=oops", "test=2"},
hasError: false,
expected: map[string]string{
"test": "2",
"flag": "oops",
},
},
} {
got, err := ParseLogOptions(tc.driver, tc.logOpts)
if err == nil && tc.hasError {
t.Fatalf("[%d case] should have error here, but got nothing", idx)
}
if err != nil && !tc.hasError {
t.Fatalf("[%d case] should have no error here, but got error(%v)", idx, err)
}

if !reflect.DeepEqual(got, tc.expected) {
t.Fatalf("[%d case] should have (%v), but got (%v)", idx, tc.expected, got)
}
}
}
4 changes: 4 additions & 0 deletions cli/common_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func addCommonFlags(flagSet *pflag.FlagSet) *container {
flagSet.StringVar(&c.ipcMode, "ipc", "", "IPC namespace to use")
flagSet.StringSliceVarP(&c.labels, "label", "l", nil, "Set labels for a container")

// log driver and log options
flagSet.StringVar(&c.logDriver, "log-driver", "json-file", "Logging driver for the container")
flagSet.StringSliceVar(&c.logOpts, "log-opt", nil, "Log driver options")

// memory

flagSet.StringVarP(&c.memory, "memory", "m", "", "Memory limit")
Expand Down
13 changes: 13 additions & 0 deletions cli/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ type container struct {
ulimit Ulimit
pidsLimit int64

// log driver and log option
logDriver string
logOpts []string

//add for rich container mode
rich bool
richMode string
Expand Down Expand Up @@ -172,6 +176,11 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {
return nil, err
}

logOpts, err := opts.ParseLogOptions(c.logDriver, c.logOpts)
if err != nil {
return nil, err
}

config := &types.ContainerCreateConfig{
ContainerConfig: types.ContainerConfig{
Tty: c.tty,
Expand Down Expand Up @@ -242,6 +251,10 @@ func (c *container) config() (*types.ContainerCreateConfig, error) {
CapDrop: c.capDrop,
PortBindings: portBindings,
OomScoreAdj: c.oomScoreAdj,
LogConfig: &types.LogConfig{
LogDriver: c.logDriver,
LogOpts: logOpts,
},
},

NetworkingConfig: networkingConfig,
Expand Down
5 changes: 3 additions & 2 deletions daemon/containerio/jsonfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ func (jf *jsonFile) Name() string {
}

func (jf *jsonFile) Init(opt *Option) error {
if _, err := os.Stat(opt.rootDir); err != nil {
rootDir := opt.info.ContainerRootDir
if _, err := os.Stat(rootDir); err != nil {
return err
}

logPath := filepath.Join(opt.rootDir, jsonFilePathName)
logPath := filepath.Join(rootDir, jsonFilePathName)
w, err := jsonfile.NewJSONLogFile(logPath, 0644)
if err != nil {
return err
Expand Down
22 changes: 18 additions & 4 deletions daemon/containerio/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import (
"os"

"github.com/alibaba/pouch/cri/stream/remotecommand"
"github.com/alibaba/pouch/daemon/logger"
)

// Option is used to pass some data into ContainerIO.
//
// FIXME(fuwei): use logger.Info to separate options and backends.
type Option struct {
info logger.Info

id string
rootDir string
stdin bool
muxDisabled bool
backends map[string]struct{}
Expand Down Expand Up @@ -41,10 +45,10 @@ func WithID(id string) func(*Option) {
}
}

// WithRootDir specified the container's root dir.
func WithRootDir(dir string) func(*Option) {
// WithLoggerInfo specified the container's logger information.
func WithLoggerInfo(info logger.Info) func(*Option) {
return func(opt *Option) {
opt.rootDir = dir
opt.info = info
}
}

Expand Down Expand Up @@ -82,6 +86,16 @@ func WithJSONFile() func(*Option) {
}
}

// WithSyslog specified the syslog backend.
func WithSyslog() func(*Option) {
return func(opt *Option) {
if opt.backends == nil {
opt.backends = make(map[string]struct{})
}
opt.backends["syslog"] = struct{}{}
}
}

// WithHijack specified the hijack backend.
func WithHijack(hi http.Hijacker, upgrade bool) func(*Option) {
return func(opt *Option) {
Expand Down
73 changes: 73 additions & 0 deletions daemon/containerio/syslog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package containerio

import (
"io"

"github.com/alibaba/pouch/daemon/logger"
"github.com/alibaba/pouch/daemon/logger/syslog"
)

func init() {
Register(func() Backend {
return &syslogging{}
})
}

type customWriter struct {
w func(p []byte) (int, error)
}

func (cw *customWriter) Write(p []byte) (int, error) {
return cw.w(p)
}

type syslogging struct {
w *syslog.Syslog
}

func (s *syslogging) Init(opt *Option) error {
w, err := syslog.NewSyslog(opt.info)
if err != nil {
return err
}
s.w = w
return nil
}

func (s *syslogging) Name() string {
return "syslog"
}

func (s *syslogging) In() io.Reader {
return nil
}

func (s *syslogging) Out() io.Writer {
return &customWriter{w: s.sourceWriteFunc("stdout")}
}

func (s *syslogging) Err() io.Writer {
return &customWriter{w: s.sourceWriteFunc("stderr")}
}

func (s *syslogging) Close() error {
return s.w.Close()
}

func (s *syslogging) sourceWriteFunc(source string) func([]byte) (int, error) {
return func(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}

msg := &logger.LogMessage{
Source: source,
Line: p,
}

if err := s.w.WriteLogMessage(msg); err != nil {
return 0, err
}
return len(p), nil
}
}
45 changes: 45 additions & 0 deletions daemon/logger/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package logger

import (
"github.com/alibaba/pouch/pkg/utils"
)

// Info provides container information for log driver.
//
// TODO(fuwei): add more fields.
type Info struct {
LogConfig map[string]string

ContainerID string
ContainerName string
ContainerImageID string
ContainerLabels map[string]string
ContainerRootDir string

DaemonName string
}

// ID returns the container truncated ID.
func (i *Info) ID() string {
return utils.TruncateID(i.ContainerID)
}

// FullID returns the container ID.
func (i *Info) FullID() string {
return i.ContainerID
}

// Name returns the container name.
func (i *Info) Name() string {
return i.ContainerName
}

// ImageID returns the container's image truncated ID.
func (i *Info) ImageID() string {
return utils.TruncateID(i.ContainerImageID)
}

// ImageFullID returns the container's image ID.
func (i *Info) ImageFullID() string {
return i.ContainerImageID
}
28 changes: 28 additions & 0 deletions daemon/logger/loggerutils/tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package loggerutils

import (
"bytes"

"github.com/alibaba/pouch/daemon/logger"
"github.com/alibaba/pouch/pkg/utils/templates"
)

// GenerateLogTag returns a tag which can be used for different log drivers
// based on the container.
func GenerateLogTag(info logger.Info, defaultTemplate string) (string, error) {
tagTemplate := info.LogConfig["tag"]
if tagTemplate == "" {
tagTemplate = defaultTemplate
}

tmpl, err := templates.NewParse("logtag", tagTemplate)
if err != nil {
return "", err
}

buf := bytes.Buffer{}
if err := tmpl.Execute(&buf, &info); err != nil {
return "", err
}
return buf.String(), nil
}
Loading