Logrus: How to have same format when writing to file as well as terminal?

Created on 18 Nov 2019  ·  5Comments  ·  Source: sirupsen/logrus

Hi,

I am writing an application where I want my logger to do 3 things (and how I :

  1. Have different level of logging ✅
  2. Includes timestamp and filename ✅
  3. Ability to write to file as well as to terminal ⚠️

I am looking for guidance for point 3. As of now, this is what i am doing to 'hack' around this feature:

logger := log.New()

logFile, err := os.OpenFile("logs.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
    panic(fmt.Sprintf("[Error]: %s", err))
}

mw := io.MultiWriter(os.Stdout, logFile)
logger.SetOutput(mw)

logger.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
    ForceColors:   true,
})

logger.Debug("Hello from Debug")
logger.Info("Hello from info")

This has the following outputs:

  1. Terminal:
INFO[2019-11-18T14:19:26Z] Hello from info                              
WARN[2019-11-18T14:19:26Z] Hello from warn 
  1. File
 INFO[2019-11-18T14:19:26Z] Hello from info                              
WARN[2019-11-18T14:19:26Z] Hello from warn  

Any ideas how I can make the File output look exactly the same as the Terminal one?

Note: I looked at https://github.com/sirupsen/logrus/issues/784 (which is also referenced in https://github.com/sirupsen/logrus/issues/888 and https://github.com/sirupsen/logrus/issues/780) but #784 changes the formatting to JSON (which is not what I am looking for)

question

Most helpful comment

@utdrmac Once #1184 is done you will be able to do:

logger.SetOutput(ioutil.Discard) // Send all logs to nowhere by default

logger.AddHook(&Hook{ // Send colored format to stdout
    Writer: os.Stdout,
    LogLevels: []log.Level{
        log.WarnLevel,
    },
    Formatter: &log.TextFormatter{
                 FullTimestamp: true,
        DisableColors:    false,
    },
})

logFile, err := os.OpenFile("logs.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
    panic(fmt.Sprintf("[Error]: %s", err))
}

logger.AddHook(&Hook{ // Send uncolored format to file
    Writer: logFile,
    LogLevels: []log.Level{
        log.InfoLevel,
    },
    Formatter: &log.TextFormatter{
                 FullTimestamp: true,
        DisableColors:    true,
    },
})

If you need the solution right now you can use the logger output for the console and then lsfhook (or another hook for the file output.

logger.SetOutput(os.Stdout) // I think this is the default and not needed.

logger.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
    ForceColors:   true,
})

logger.AddHook(&lfshook.NewHook(
    lfshook.PathMap{
        logrus.InfoLevel:  "logs.log",
        logrus.ErrorLevel: "logs.log",
                ...
    },
    &log.TextFormatter{
              FullTimestamp: true,
              DisableColors:   true,
        },
)

All 5 comments

I think those characters are used for colors. I see you are using ForceColors. If you disable it, I think they will go away.

log.SetFormatter(&log.TextFormatter{
    DisableColors: true,
})

@MinweiShen How can I have colors on terminal but no colors in log file?

@utdrmac You can use two hooks instead of io.MultiWriter. Then you configure the terminal hook to use TextFormatter with DisableColors: true, and the file hook to use TextFormatter with DisableColors: false.

@gguridi Two &writer.Hook hooks? How do I configure different formatters for different hooks?

@utdrmac Once #1184 is done you will be able to do:

logger.SetOutput(ioutil.Discard) // Send all logs to nowhere by default

logger.AddHook(&Hook{ // Send colored format to stdout
    Writer: os.Stdout,
    LogLevels: []log.Level{
        log.WarnLevel,
    },
    Formatter: &log.TextFormatter{
                 FullTimestamp: true,
        DisableColors:    false,
    },
})

logFile, err := os.OpenFile("logs.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
    panic(fmt.Sprintf("[Error]: %s", err))
}

logger.AddHook(&Hook{ // Send uncolored format to file
    Writer: logFile,
    LogLevels: []log.Level{
        log.InfoLevel,
    },
    Formatter: &log.TextFormatter{
                 FullTimestamp: true,
        DisableColors:    true,
    },
})

If you need the solution right now you can use the logger output for the console and then lsfhook (or another hook for the file output.

logger.SetOutput(os.Stdout) // I think this is the default and not needed.

logger.SetFormatter(&log.TextFormatter{
    FullTimestamp: true,
    ForceColors:   true,
})

logger.AddHook(&lfshook.NewHook(
    lfshook.PathMap{
        logrus.InfoLevel:  "logs.log",
        logrus.ErrorLevel: "logs.log",
                ...
    },
    &log.TextFormatter{
              FullTimestamp: true,
              DisableColors:   true,
        },
)
Was this page helpful?
0 / 5 - 0 ratings