package logs import ( "errors" "fmt" "io" "os" "path/filepath" "strings" "github.com/dokku/dokku/plugins/common" dockeroptions "github.com/dokku/dokku/plugins/docker-options" ) // TriggerDockerArgsProcessDeploy outputs the logs plugin docker options for an app func TriggerDockerArgsProcessDeploy(appName string) error { stdin, err := io.ReadAll(os.Stdin) if err != nil { return err } allowedDrivers := map[string]bool{ "local": true, "json-file": true, } ignoreMaxSize := false options, err := dockeroptions.GetDockerOptionsForPhase(appName, "deploy") if err != nil { return err } hasDriverOpt := false for _, option := range options { if !strings.HasPrefix(option, "--log-driver=") { continue } hasDriverOpt = true logDriver := strings.TrimPrefix(option, "--log-driver=") if !allowedDrivers[logDriver] { ignoreMaxSize = true } break } if !hasDriverOpt { result, _ := common.CallExecCommand(common.ExecCommandInput{ Command: common.DockerBin(), Args: []string{"system", "info", "--format", "{{ .LoggingDriver }}"}, }) if !allowedDrivers[result.StdoutContents()] { ignoreMaxSize = true } } if !ignoreMaxSize { maxSize := common.PropertyGet("logs", appName, "max-size") if maxSize == "" { maxSize = common.PropertyGetDefault("logs", "--global", "max-size", MaxSize) } if maxSize != "unlimited" { fmt.Printf(" --log-opt=max-size=%s ", maxSize) } } fmt.Print(string(stdin)) return nil } // TriggerInstall initializes log configuration func TriggerInstall() error { if err := common.PropertySetup("logs"); err != nil { return fmt.Errorf("Unable to install the logs plugin: %s", err.Error()) } if err := common.SetupAppData("logs"); err != nil { return err } logDirectory := filepath.Join(common.MustGetEnv("DOKKU_LOGS_DIR"), "apps") if err := os.MkdirAll(logDirectory, 0755); err != nil { return err } return common.SetPermissions(common.SetPermissionInput{ Filename: logDirectory, Mode: os.FileMode(0755), }) } // TriggerLogsGetProperty writes the logs key to stdout for a given app container func TriggerLogsGetProperty(appName string, key string) error { if key != "max-size" { return errors.New("Invalid logs property specified") } value := common.PropertyGet("logs", appName, "max-size") if value == "" { value = common.PropertyGetDefault("logs", "--global", "max-size", MaxSize) } fmt.Println(value) return nil } // TriggerPostAppCloneSetup creates new logs files and regenerates the vector // config so that the clone gets a source of its own for the sink it inherited func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error { err := common.PropertyClone("logs", oldAppName, newAppName) if err != nil { return err } if err := common.CloneAppData("logs", oldAppName, newAppName); err != nil { return err } regenerateVectorConfig() return nil } // TriggerPostAppRename removes the old app data func TriggerPostAppRename(oldAppName string, newAppName string) error { return common.MigrateAppDataDirectory("logs", oldAppName, newAppName) } // TriggerPostAppRenameSetup renames logs files and regenerates the vector config. // Both app roots exist at this point, but the old app no longer has any logs // properties, so it drops out of the generated config. func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error { if err := common.PropertyClone("logs", oldAppName, newAppName); err != nil { return err } if err := common.PropertyDestroy("logs", oldAppName); err != nil { return err } if err := common.CloneAppData("logs", oldAppName, newAppName); err != nil { return err } regenerateVectorConfig() return nil } // TriggerPostCreate ensures apps have the correct data directory structure func TriggerPostCreate(appName string) error { return common.CreateAppDataDirectory("logs", appName) } // TriggerPostDelete destroys the logs property for a given app container and // regenerates the vector config. The regeneration runs after the properties are // destroyed so that the app drops out of the config even though its app root is // only removed later in the destroy flow. func TriggerPostDelete(appName string) error { dataErr := common.RemoveAppDataDirectory("logs", appName) propertyErr := common.PropertyDestroy("logs", appName) regenerateVectorConfig() if dataErr != nil { return dataErr } return propertyErr }