aboutsummaryrefslogtreecommitdiff
path: root/core/setup/errors.go
blob: 0b392ec99e7d36df8dc74d67358236b644167694 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package setup

import (
	"io"
	"log"
	"os"

	"github.com/hashicorp/go-syslog"
	"github.com/miekg/coredns/middleware"
	"github.com/miekg/coredns/middleware/errors"
)

// Errors configures a new errors middleware instance.
func Errors(c *Controller) (middleware.Middleware, error) {
	handler, err := errorsParse(c)
	if err != nil {
		return nil, err
	}

	// Open the log file for writing when the server starts
	c.Startup = append(c.Startup, func() error {
		var err error
		var writer io.Writer

		switch handler.LogFile {
		case "visible":
			handler.Debug = true
		case "stdout":
			writer = os.Stdout
		case "stderr":
			writer = os.Stderr
		case "syslog":
			writer, err = gsyslog.NewLogger(gsyslog.LOG_ERR, "LOCAL0", "caddy")
			if err != nil {
				return err
			}
		default:
			if handler.LogFile == "" {
				writer = os.Stderr // default
				break
			}

			var file *os.File
			file, err = os.OpenFile(handler.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
			if err != nil {
				return err
			}
			if handler.LogRoller != nil {
				file.Close()

				handler.LogRoller.Filename = handler.LogFile

				writer = handler.LogRoller.GetLogWriter()
			} else {
				writer = file
			}
		}

		handler.Log = log.New(writer, "", 0)
		return nil
	})

	return func(next middleware.Handler) middleware.Handler {
		handler.Next = next
		return handler
	}, nil
}

func errorsParse(c *Controller) (*errors.ErrorHandler, error) {
	// Very important that we make a pointer because the Startup
	// function that opens the log file must have access to the
	// same instance of the handler, not a copy.
	handler := &errors.ErrorHandler{}

	optionalBlock := func() (bool, error) {
		var hadBlock bool

		for c.NextBlock() {
			hadBlock = true

			what := c.Val()
			if !c.NextArg() {
				return hadBlock, c.ArgErr()
			}
			where := c.Val()

			if what == "log" {
				if where == "visible" {
					handler.Debug = true
				} else {
					handler.LogFile = where
					if c.NextArg() {
						if c.Val() == "{" {
							c.IncrNest()
							logRoller, err := parseRoller(c)
							if err != nil {
								return hadBlock, err
							}
							handler.LogRoller = logRoller
						}
					}
				}
			}
		}
		return hadBlock, nil
	}

	for c.Next() {
		// weird hack to avoid having the handler values overwritten.
		if c.Val() == "}" {
			continue
		}
		// Configuration may be in a block
		hadBlock, err := optionalBlock()
		if err != nil {
			return handler, err
		}

		// Otherwise, the only argument would be an error log file name or 'visible'
		if !hadBlock {
			if c.NextArg() {
				if c.Val() == "visible" {
					handler.Debug = true
				} else {
					handler.LogFile = c.Val()
				}
			}
		}
	}

	return handler, nil
}