Skip to content

Commit

Permalink
logging: allow to setup default log output in global
Browse files Browse the repository at this point in the history
  • Loading branch information
jkellerer committed Oct 29, 2023
1 parent 63f8faf commit f6547d0
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 62 deletions.
9 changes: 0 additions & 9 deletions commands_display.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,15 +158,6 @@ func displayResticHelp(output io.Writer, configuration *config.Config, flags com
out, closer := displayWriter(output, flags)
defer closer()

// try to load the config
if configuration == nil {
if file, err := filesearch.FindConfigurationFile(flags.config); err == nil {
if configuration, err = config.LoadFile(file, flags.format); err != nil {
configuration = nil
}
}
}

resticBinary := ""
if configuration != nil {
if section, err := configuration.GetGlobalSection(); err == nil {
Expand Down
1 change: 1 addition & 0 deletions config/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Global struct {
ShellBinary []string `mapstructure:"shell" default:"auto" examples:"sh;bash;pwsh;powershell;cmd" description:"The shell that is used to run commands (default is OS specific)"`
MinMemory uint64 `mapstructure:"min-memory" default:"100" description:"Minimum available memory (in MB) required to run any commands - see https://creativeprojects.github.io/resticprofile/usage/memory/"`
Scheduler string `mapstructure:"scheduler" description:"Leave blank for the default scheduler or use \"crond\" to select cron on supported operating systems"`
Log string `mapstructure:"log" default:"" description:"Sets the default log destination to be used if not specified in '--log' or 'schedule-log' - see https://creativeprojects.github.io/resticprofile/configuration/logs/"`
LegacyArguments bool `mapstructure:"legacy-arguments" default:"false" deprecated:"0.20.0" description:"Legacy, broken arguments mode of resticprofile before version 0.15"`
SystemdUnitTemplate string `mapstructure:"systemd-unit-template" default:"" description:"File containing the go template to generate a systemd unit - see https://creativeprojects.github.io/resticprofile/schedules/systemd/"`
SystemdTimerTemplate string `mapstructure:"systemd-timer-template" default:"" description:"File containing the go template to generate a systemd timer - see https://creativeprojects.github.io/resticprofile/schedules/systemd/"`
Expand Down
49 changes: 49 additions & 0 deletions docs/content/configuration/logs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ You can redirect the logs to a local file, a temporary file or a syslog server.
## Destination

The log destination syntax is a such:
* `-` {{% icon icon="arrow-right" %}} redirects all the logs to the console / stdout (is the default log destination)
* `filename` {{% icon icon="arrow-right" %}} redirects all the logs to the local file called **filename**
* `temp:filename` {{% icon icon="arrow-right" %}} redirects all the logs to a temporary file available during the whole session, and deleted afterwards.
* `tcp://syslog_server:514` or `udp://syslog_server:514` {{% icon icon="arrow-right" %}} redirects all the logs to the **syslog** server.
Expand All @@ -19,6 +20,54 @@ The log destination syntax is a such:
If the location cannot be opened, **resticprofile** will default to send the logs to the console.
{{% /notice %}}

## Default

You can adjust the default log destination in the `global` section:

{{< tabs groupid="config-with-json" >}}
{{% tab title="toml" %}}

```toml
version = "1"

[global]
log = "resticprofile.log"
```

{{% /tab %}}
{{% tab title="yaml" %}}

```yaml
version: "1"

global:
log: "resticprofile.log"
```
{{% /tab %}}
{{% tab title="hcl" %}}
```hcl
"global" {
"log" = "resticprofile.log"
}
```

{{% /tab %}}
{{% tab title="json" %}}

```json
{
"version": "1",
"global": {
"log": "resticprofile.log"
}
}
```

{{% /tab %}}
{{< /tabs >}}

## Command line

You can redirect the logs on the command line with the `--log` flag:
Expand Down
113 changes: 60 additions & 53 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"errors"
"fmt"
"math/rand"
"os"
Expand Down Expand Up @@ -75,53 +76,55 @@ func main() {
}

// help
if flags.help || flagErr == pflag.ErrHelp {
if flags.help || errors.Is(flagErr, pflag.ErrHelp) {
_ = displayHelpCommand(os.Stdout, commandRequest{ownCommands: ownCommands, flags: flags, args: args})
return
}

// setting up the logger - we can start logging right after
if flags.isChild {
// use a remote logger
client := remote.NewClient(flags.parentPort)
setupRemoteLogger(flags, client)

// also redirect the terminal through the client
term.SetAllOutput(term.NewRemoteTerm(client))
// logger setup logic - is delayed until config was loaded (or attempted)
setupLogging := func(global *config.Global) (logCloser func()) {
logCloser = func() {}

// If this is running in elevated mode we'll need to send a finished signal
if flags.isChild {
defer func(port int) {
client := remote.NewClient(port)
client.Done()
}(flags.parentPort)
}
// use a remote logger
client := remote.NewClient(flags.parentPort)
logCloser = func() { _ = client.Done() }
setupRemoteLogger(flags, client)

} else if flags.log != "" {
handle, err := setupTargetLogger(flags)
if err != nil {
// back to a console logger
setupConsoleLogger(flags)
clog.Errorf("cannot open log target: %s", err)
// also redirect the terminal through the client
term.SetAllOutput(term.NewRemoteTerm(client))
} else {
// close the log file at the end
defer handle.Close()
if flags.log == "" && global != nil {
flags.log = global.Log
}
if flags.log != "" && flags.log != "-" {
if closer, err := setupTargetLogger(flags); err == nil {
logCloser = func() { _ = closer.Close() }
} else {
// fallback to a console logger
setupConsoleLogger(flags)
clog.Errorf("cannot open log target: %s", err)
}
} else {
// use the console logger
setupConsoleLogger(flags)
}
}

} else {
// Use the console logger
setupConsoleLogger(flags)
return
}

// keep this one last if possible (so it will be first at the end)
defer showPanicData()

banner()

// resticprofile own commands (configuration file NOT loaded)
// resticprofile own commands (configuration file may NOT be loaded)
if len(flags.resticArgs) > 0 {
if ownCommands.Exists(flags.resticArgs[0], false) {
err = ownCommands.Run(nil, flags.resticArgs[0], flags, flags.resticArgs[1:])
// try to load the config and setup logging for own command
configuration, global, _ := loadConfig(flags, true)
defer setupLogging(global)()
err = ownCommands.Run(configuration, flags.resticArgs[0], flags, flags.resticArgs[1:])
if err != nil {
clog.Error(err)
exitCode = 1
Expand All @@ -131,6 +134,15 @@ func main() {
}
}

// Load the mandatory configuration and setup logging (before returning on error)
c, global, err := loadConfig(flags, false)
defer setupLogging(global)()
if err != nil {
clog.Error(err)
exitCode = 1
return
}

// check if we're running on battery
if flags.ignoreOnBattery > 0 && flags.ignoreOnBattery <= constants.BatteryFull {
battery, charge, err := IsRunningOnBattery()
Expand All @@ -152,30 +164,6 @@ func main() {
}
}

configFile, err := filesearch.FindConfigurationFile(flags.config)
if err != nil {
clog.Error(err)
exitCode = 1
return
}
if configFile != flags.config {
clog.Infof("using configuration file: %s", configFile)
}

c, err := config.LoadFile(configFile, flags.format)
if err != nil {
clog.Errorf("cannot load configuration file: %v", err)
exitCode = 1
return
}

global, err := c.GetGlobalSection()
if err != nil {
clog.Errorf("cannot load global configuration: %v", err)
exitCode = 1
return
}

// prevent computer from sleeping
var caffeinate *preventsleep.Caffeinate
if global.PreventSleep {
Expand Down Expand Up @@ -309,6 +297,25 @@ func banner() {
clog.Debugf("resticprofile %s compiled with %s", version, runtime.Version())
}

func loadConfig(flags commandLineFlags, silent bool) (cfg *config.Config, global *config.Global, err error) {
var configFile string
if configFile, err = filesearch.FindConfigurationFile(flags.config); err == nil {
if configFile != flags.config && !silent {
clog.Infof("using configuration file: %s", configFile)
}

if cfg, err = config.LoadFile(configFile, flags.format); err == nil {
global, err = cfg.GetGlobalSection()
if err != nil {
err = fmt.Errorf("cannot load global configuration: %w", err)
}
} else {
err = fmt.Errorf("cannot load configuration file: %w", err)
}
}
return
}

func setPriority(nice int, class string) error {
var err error

Expand Down

0 comments on commit f6547d0

Please sign in to comment.