Skip to content

Commit

Permalink
logging: Customize log file permissions (#6314)
Browse files Browse the repository at this point in the history
Adding a "mode" option to overwrite the default logfile permissions.
Default remains "0600" which is the one currently used by lumberjack.
  • Loading branch information
ririsoft authored Jun 6, 2024
1 parent 3f1add6 commit 101d3e7
Show file tree
Hide file tree
Showing 3 changed files with 426 additions and 2 deletions.
65 changes: 63 additions & 2 deletions modules/logging/filewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package logging

import (
"encoding/json"
"fmt"
"io"
"math"
Expand All @@ -33,6 +34,43 @@ func init() {
caddy.RegisterModule(FileWriter{})
}

// fileMode is a string made of 1 to 4 octal digits representing
// a numeric mode as specified with the `chmod` unix command.
// `"0777"` and `"777"` are thus equivalent values.
type fileMode os.FileMode

// UnmarshalJSON satisfies json.Unmarshaler.
func (m *fileMode) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
return io.EOF
}

var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}

mode, err := parseFileMode(s)
if err != nil {
return err
}

*m = fileMode(mode)
return err
}

// parseFileMode parses a file mode string,
// adding support for `chmod` unix command like
// 1 to 4 digital octal values.
func parseFileMode(s string) (os.FileMode, error) {
modeStr := fmt.Sprintf("%04s", s)
mode, err := strconv.ParseUint(modeStr, 8, 32)
if err != nil {
return 0, err
}
return os.FileMode(mode), nil
}

// FileWriter can write logs to files. By default, log files
// are rotated ("rolled") when they get large, and old log
// files get deleted, to ensure that the process does not
Expand All @@ -41,6 +79,10 @@ type FileWriter struct {
// Filename is the name of the file to write.
Filename string `json:"filename,omitempty"`

// The file permissions mode.
// 0600 by default.
Mode fileMode `json:"mode,omitempty"`

// Roll toggles log rolling or rotation, which is
// enabled by default.
Roll *bool `json:"roll,omitempty"`
Expand Down Expand Up @@ -100,6 +142,10 @@ func (fw FileWriter) WriterKey() string {

// OpenWriter opens a new file writer.
func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
if fw.Mode == 0 {
fw.Mode = 0o600
}

// roll log files by default
if fw.Roll == nil || *fw.Roll {
if fw.RollSizeMB == 0 {
Expand All @@ -116,6 +162,9 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
fw.RollKeepDays = 90
}

f_tmp, _ := os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(fw.Mode))
f_tmp.Close()

return &lumberjack.Logger{
Filename: fw.Filename,
MaxSize: fw.RollSizeMB,
Expand All @@ -127,12 +176,13 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
}

// otherwise just open a regular file
return os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666)
return os.OpenFile(fw.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(fw.Mode))
}

// UnmarshalCaddyfile sets up the module from Caddyfile tokens. Syntax:
//
// file <filename> {
// mode <mode>
// roll_disabled
// roll_size <size>
// roll_uncompressed
Expand All @@ -150,7 +200,7 @@ func (fw FileWriter) OpenWriter() (io.WriteCloser, error) {
// The roll_keep_for duration has day resolution.
// Fractional values are rounded up to the next whole number of days.
//
// If any of the roll_size, roll_keep, or roll_keep_for subdirectives are
// If any of the mode, roll_size, roll_keep, or roll_keep_for subdirectives are
// omitted or set to a zero value, then Caddy's default value for that
// subdirective is used.
func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
Expand All @@ -165,6 +215,17 @@ func (fw *FileWriter) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {

for d.NextBlock(0) {
switch d.Val() {
case "mode":
var modeStr string
if !d.AllArgs(&modeStr) {
return d.ArgErr()
}
mode, err := parseFileMode(modeStr)
if err != nil {
return d.Errf("parsing mode: %v", err)
}
fw.Mode = fileMode(mode)

case "roll_disabled":
var f bool
fw.Roll = &f
Expand Down
Loading

6 comments on commit 101d3e7

@ta2013
Copy link

@ta2013 ta2013 commented on 101d3e7 Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this mode with Caddyfile now? I tried add { mode 644 } then validate the config:
Error: setting up default log: loading log writer module: loading module 'file': decoding module config: caddy.logging.writers.file: json: cannot unmarshal number into Go struct field FileWriter.mode of type string

@mholt
Copy link
Member

@mholt mholt commented on 101d3e7 Jun 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ririsoft Is this something you can reproduce? I haven't had a chance to test it

@ririsoft
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I can reproduce.

I did full end to end testing when I only implemented the CaddyFile config.

I then added support for JSON but did not do full end to end testing again, assuming the unittests were enough.
I am really sorry about that.

I was missing an implementation of MarshallJson since I only implemented UnMarshalJSON.

Shall I submit a new PR to fix it or you want a revert first ?

@francislavoie
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just fix it. We don't provide any guarantees about the master branch.

@ririsoft
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#6383 should fix it.

@mholt
Copy link
Member

@mholt mholt commented on 101d3e7 Jun 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the high-quality contribution! And patch :)

Please sign in to comment.