main.go (125 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package main denotes the entry of shim loggers for Containerd.
package main
import (
"fmt"
"os"
"runtime"
"github.com/aws/shim-loggers-for-containerd/debug"
"github.com/aws/shim-loggers-for-containerd/logger"
"github.com/aws/shim-loggers-for-containerd/logger/awslogs"
"github.com/aws/shim-loggers-for-containerd/logger/fluentd"
"github.com/aws/shim-loggers-for-containerd/logger/splunk"
"github.com/containerd/containerd/runtime/v2/logging"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
func init() {
initCommonLogOpts()
initWindowsOpts()
initDockerConfigOpts()
initAWSLogsOpts()
initFluentdOpts()
initSplunkOpts()
}
func main() {
pflag.Parse()
if err := run(); err != nil {
debug.SendEventsToLog(logger.DaemonName, err.Error(), debug.ERROR, 1)
os.Exit(1)
}
}
func run() error {
if err := viper.BindPFlags(pflag.CommandLine); err != nil {
return fmt.Errorf("unable to bind command line flags: %w", err)
}
globalArgs, err := getGlobalArgs()
if err != nil {
return fmt.Errorf("unable to get global arguments: %w", err)
}
// Read the Windows specific options and set the environment up accordingly
if runtime.GOOS == "windows" {
windowsArgs := getWindowsArgs()
err = setWindowsEnv(windowsArgs.LogFileDir, globalArgs.ContainerName, windowsArgs.ProxyEnvVar)
if err != nil {
return fmt.Errorf("failed to set up Windows env with options: %w", err)
}
defer cleanWindowsEnv(windowsArgs.ProxyEnvVar)
}
debug.Verbose = viper.GetBool(verboseKey)
if debug.Verbose {
debug.SendEventsToLog(logger.DaemonName, "Using verbose mode", debug.INFO, 0)
// If in Verbose mode, start a goroutine to catch os signal and print stack trace
debug.StartStackTraceHandler()
}
// Set UID and/or GID of main goroutine/shim logger process if specified.
// If you are building with go version includes the following commit, you only need
// to call this once in main goroutine. Otherwise you need call this function in all
// goroutines to let this syscall work properly.
// Commit: https://github.com/golang/go/commit/d1b1145cace8b968307f9311ff611e4bb810710c
// TODO: remove the above comment once the changes are released: https://go-review.googlesource.com/c/go/+/210639
if err = logger.SetUIDAndGID(globalArgs.UID, globalArgs.GID); err != nil {
return err
}
logDriver := globalArgs.LogDriver
debug.SendEventsToLog(logger.DaemonName, "Driver: "+logDriver, debug.INFO, 0)
switch logDriver {
case awslogsDriverName:
if err := runAWSLogsDriver(globalArgs); err != nil {
return fmt.Errorf("unable to run awslogs driver: %w", err)
}
case fluentdDriverName:
runFluentdDriver(globalArgs)
case splunkDriverName:
if err := runSplunkDriver(globalArgs); err != nil {
return fmt.Errorf("unable to run splunk driver: %w", err)
}
default:
return fmt.Errorf("unknown log driver: %s", logDriver)
}
return nil
}
func runAWSLogsDriver(globalArgs *logger.GlobalArgs) error {
args, err := getAWSLogsArgs()
if err != nil {
return fmt.Errorf("unable to get awslogs specified arguments: %w", err)
}
loggerArgs := awslogs.InitLogger(globalArgs, args)
logging.Run(loggerArgs.RunLogDriver)
return nil
}
func runFluentdDriver(globalArgs *logger.GlobalArgs) {
args := getFluentdArgs()
loggerArgs := fluentd.InitLogger(globalArgs, args)
logging.Run(loggerArgs.RunLogDriver)
}
func runSplunkDriver(globalArgs *logger.GlobalArgs) error {
dockerConfigs, err := getDockerConfigs()
if err != nil {
return fmt.Errorf("unable to get docker config arguments: %w", err)
}
args, err := getSplunkArgs()
if err != nil {
return fmt.Errorf("unable to get splunk specified arguments: %w", err)
}
loggerArgs := splunk.InitLogger(globalArgs, dockerConfigs, args)
logging.Run(loggerArgs.RunLogDriver)
return nil
}
// setWindowsEnv reads the Windows options and sets them up.
func setWindowsEnv(logDir, containerName, proxyEnvVar string) error {
if logDir != "" {
err := debug.SetLogFilePath(logDir, containerName)
if err != nil {
// Will include an error line if log-file-dir option is set for non-Windows in logs.
// Will ignore and continue to log with journald.
debug.SendEventsToLog(logger.DaemonName, err.Error(), debug.ERROR, 1)
return err
}
}
// proxyEnvVar will set the HTTP_PROXY and HTTPS_PROXY environment variables.
if proxyEnvVar != "" {
err := os.Setenv("HTTP_PROXY", proxyEnvVar)
if err != nil {
return err
}
err = os.Setenv("HTTPS_PROXY", proxyEnvVar)
if err != nil {
return err
}
}
return nil
}
// cleanWindowsEnv flushes the file logs for Windows and unsets the proxy env variables.
func cleanWindowsEnv(proxyEnvVar string) {
debug.FlushLog()
if proxyEnvVar != "" {
os.Unsetenv("HTTP_PROXY") //nolint:errcheck // unset env
os.Unsetenv("HTTPS_PROXY") //nolint:errcheck // unset env
}
}