Skip to content

Commit

Permalink
Merge pull request #1354 from manugupt1/3plog
Browse files Browse the repository at this point in the history
Implements logURI to support 3rd party ctrd shim logger
  • Loading branch information
AkihiroSuda committed Sep 11, 2022
2 parents e57225e + 0273c00 commit 660680b
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 28 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ Logging flags:
- :whale: `--log-opt=fluentd-sub-second-precision=<true|false>`: Enable sub-second precision for fluentd. The default value is false.
- :nerd_face: `--log-opt=fluentd-async-reconnect-interval=<1s|1ms>`: The time to wait before retrying to reconnect to fluentd. The default value is 0s.
- :nerd_face: `--log-opt=fluentd-request-ack=<true|false>`: Enable request ack for fluentd. The default value is false.
- :nerd_face: Accepts a LogURI which is a containerd shim logger. A scheme must be specified for the URI. Example: `nerdctl run -d --log-driver binary:///usr/bin/ctr-journald-shim docker.io/library/hello-world:latest`. An implementation of shim logger can be found at (https://github.com/containerd/containerd/tree/dbef1d56d7ebc05bc4553d72c419ed5ce025b05d/runtime/v2#logging)


Shared memory flags:
- :whale: `--ipc`: IPC namespace to use
Expand Down
64 changes: 36 additions & 28 deletions cmd/nerdctl/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func setCreateFlags(cmd *cobra.Command) {

// #region logging flags
// log-opt needs to be StringArray, not StringSlice, to prevent "env=os,customer" from being split to {"env=os", "customer"}
cmd.Flags().String("log-driver", "json-file", "Logging driver for the container")
cmd.Flags().String("log-driver", "json-file", "Logging driver for the container. Default is json-file. It also supports logURI (eg: --log-driver binary://<path>)")
cmd.RegisterFlagCompletionFunc("log-driver", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return logging.Drivers(), cobra.ShellCompDirectiveNoFileComp
})
Expand Down Expand Up @@ -497,33 +497,41 @@ func createContainer(cmd *cobra.Command, ctx context.Context, client *containerd
if err != nil {
return nil, nil, err
}
logOptMap, err := parseKVStringsMapFromLogOpt(cmd, logDriver)
if err != nil {
return nil, nil, err
}
logDriverInst, err := logging.GetDriver(logDriver, logOptMap)
if err != nil {
return nil, nil, err
}
if err := logDriverInst.Init(dataStore, ns, id); err != nil {
return nil, nil, err
}
logConfig := &logging.LogConfig{
Driver: logDriver,
Opts: logOptMap,
}
logConfigB, err := json.Marshal(logConfig)
if err != nil {
return nil, nil, err
}
logConfigFilePath := logging.LogConfigFilePath(dataStore, ns, id)
if err = os.WriteFile(logConfigFilePath, logConfigB, 0600); err != nil {
return nil, nil, err
}
if lu, err := generateLogURI(dataStore); err != nil {
return nil, nil, err
} else if lu != nil {
logURI = lu.String()

// check if log driver is a valid uri. If it is a valid uri and scheme is not
if u, err := url.Parse(logDriver); err == nil && u.Scheme != "" {
logURI = logDriver
} else {
logOptMap, err := parseKVStringsMapFromLogOpt(cmd, logDriver)
if err != nil {
return nil, nil, err
}
logDriverInst, err := logging.GetDriver(logDriver, logOptMap)
if err != nil {
return nil, nil, err
}
if err := logDriverInst.Init(dataStore, ns, id); err != nil {
return nil, nil, err
}
logConfig := &logging.LogConfig{
Driver: logDriver,
Opts: logOptMap,
}
logConfigB, err := json.Marshal(logConfig)
if err != nil {
return nil, nil, err
}
logConfigFilePath := logging.LogConfigFilePath(dataStore, ns, id)
if err = os.WriteFile(logConfigFilePath, logConfigB, 0600); err != nil {
return nil, nil, err
}
if lu, err := generateLogURI(dataStore); err != nil {
return nil, nil, err
} else if lu != nil {
logrus.Debugf("generated log driver: %s", lu.String())

logURI = lu.String()
}
}
}

Expand Down
88 changes: 88 additions & 0 deletions cmd/nerdctl/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,3 +305,91 @@ func TestRunWithJournaldLogDriverAndLogOpt(t *testing.T) {
poll.WaitOn(t, check, poll.WithDelay(100*time.Microsecond), poll.WithTimeout(20*time.Second))
assert.Equal(t, 1, found)
}

func TestRunWithLogBinary(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("buildkit is not enabled on windows, this feature may work on windows.")
}
testutil.DockerIncompatible(t)
t.Parallel()
base := testutil.NewBase(t)
imageName := testutil.Identifier(t) + "-image"
containerName := testutil.Identifier(t)

const dockerfile = `
FROM golang:latest as builder
WORKDIR /go/src/
RUN mkdir -p logger
WORKDIR /go/src/logger
RUN echo '\
package main \n\
\n\
import ( \n\
"bufio" \n\
"context" \n\
"fmt" \n\
"io" \n\
"os" \n\
"path/filepath" \n\
"sync" \n\
\n\
"github.com/containerd/containerd/runtime/v2/logging"\n\
)\n\
func main() {\n\
logging.Run(log)\n\
}\n\
func log(ctx context.Context, config *logging.Config, ready func() error) error {\n\
var wg sync.WaitGroup \n\
wg.Add(2) \n\
// forward both stdout and stderr to temp files \n\
go copy(&wg, config.Stdout, config.ID, "stdout") \n\
go copy(&wg, config.Stderr, config.ID, "stderr") \n\
// signal that we are ready and setup for the container to be started \n\
if err := ready(); err != nil { \n\
return err \n\
} \n\
wg.Wait() \n\
return nil \n\
}\n\
\n\
func copy(wg *sync.WaitGroup, r io.Reader, id string, kind string) { \n\
f, _ := os.Create(filepath.Join(os.TempDir(), fmt.Sprintf("%s_%s.log", id, kind))) \n\
defer f.Close() \n\
defer wg.Done() \n\
s := bufio.NewScanner(r) \n\
for s.Scan() { \n\
f.WriteString(s.Text()) \n\
} \n\
}\n' >> main.go
RUN go mod init
RUN go mod tidy
RUN go build .
FROM scratch
COPY --from=builder /go/src/logger/logger /
`

buildCtx, err := createBuildContext(dockerfile)
assert.NilError(t, err)
defer os.RemoveAll(buildCtx)
tmpDir := t.TempDir()
base.Cmd("build", buildCtx, "--output", fmt.Sprintf("type=local,src=/go/src/logger/logger,dest=%s", tmpDir)).AssertOK()
defer base.Cmd("image", "rm", "-f", imageName).AssertOK()

base.Cmd("container", "rm", "-f", containerName).AssertOK()
base.Cmd("run", "-d", "--log-driver", fmt.Sprintf("binary://%s/logger", tmpDir), "--name", containerName, testutil.CommonImage,
"sh", "-euxc", "echo foo; echo bar").AssertOK()
defer base.Cmd("container", "rm", "-f", containerName)

inspectedContainer := base.InspectContainer(containerName)
bytes, err := os.ReadFile(filepath.Join(os.TempDir(), fmt.Sprintf("%s_%s.log", inspectedContainer.ID, "stdout")))
assert.NilError(t, err)
log := string(bytes)
assert.Check(t, strings.Contains(log, "foo"))
assert.Check(t, strings.Contains(log, "bar"))
}

0 comments on commit 660680b

Please sign in to comment.