619
// }
620
//
621
func parseLog(h Helper) ([]ConfigValue, error) {
622
+ return parseLogHelper(h, nil)
623
+}
624
+
625
+// parseLogHelper is used both for the parseLog directive within Server Blocks,
626
+// as well as the global "log" option for configuring loggers at the global
627
+// level. The parseAsGlobalOption parameter is used to distinguish any differing logic
628
+// between the two.
629
+func parseLogHelper(h Helper, globalLogNames map[string]struct{}) ([]ConfigValue, error) {
630
+ // When the globalLogNames parameter is passed in, we make
631
+ // modifications to the parsing behavior.
632
+ parseAsGlobalOption := globalLogNames != nil
633
+
634
var configValues []ConfigValue
635
for h.Next() {
624
- // log does not currently support any arguments
625
- if h.NextArg() {
626
- return nil, h.ArgErr()
636
+ // Logic below expects that a name is always present when a
637
+ // global option is being parsed.
638
+ var globalLogName string
639
+ if parseAsGlobalOption {
640
+ if h.NextArg() {
641
+ globalLogName = h.Val()
642
+
643
+ // Only a single argument is supported.
644
+ if h.NextArg() {
645
+ return nil, h.ArgErr()
646
+ }
647
+ } else {
648
+ // If there is no log name specified, we
649
+ // reference the default logger. See the
650
+ // setupNewDefault function in the logging
651
+ // package for where this is configured.
652
+ globalLogName = "default"
653
+ }
654
+
655
+ // Verify this name is unused.
656
+ _, used := globalLogNames[globalLogName]
657
+ if used {
658
+ return nil, h.Err("duplicate global log option for: " + globalLogName)
659
+ }
660
+ globalLogNames[globalLogName] = struct{}{}
661
+ } else {
662
+ // No arguments are supported for the server block log directive
663
+ if h.NextArg() {
664
+ return nil, h.ArgErr()
665
+ }
666
}
667
668
cl := new(caddy.CustomLog)
726
return nil, h.ArgErr()
727
}
728
729
+ case "include":
730
+ // This configuration is only allowed in the global options
731
+ if !parseAsGlobalOption {
732
+ return nil, h.ArgErr()
733
+ }
734
+ for h.NextArg() {
735
+ cl.Include = append(cl.Include, h.Val())
736
+ }
737
+
738
+ case "exclude":
739
+ // This configuration is only allowed in the global options
740
+ if !parseAsGlobalOption {
741
+ return nil, h.ArgErr()
742
+ }
743
+ for h.NextArg() {
744
+ cl.Exclude = append(cl.Exclude, h.Val())
745
+ }
746
+
747
default:
748
return nil, h.Errf("unrecognized subdirective: %s", h.Val())
749
}
750
}
751
752
var val namedCustomLog
753
+ // Skip handling of empty logging configs
754
if !reflect.DeepEqual(cl, new(caddy.CustomLog)) {
697
- logCounter, ok := h.State["logCounter"].(int)
698
- if !ok {
699
- logCounter = 0
755
+ if parseAsGlobalOption {
756
+ // Use indicated name for global log options
757
+ val.name = globalLogName
758
+ val.log = cl
759
+ } else {
760
+ // Construct a log name for server log streams
761
+ logCounter, ok := h.State["logCounter"].(int)
762
+ if !ok {
763
+ logCounter = 0
764
+ }
765
+ val.name = fmt.Sprintf("log%d", logCounter)
766
+ cl.Include = []string{"http.log.access." + val.name}
767
+ val.log = cl
768
+ logCounter++
769
+ h.State["logCounter"] = logCounter
770
}
701
- val.name = fmt.Sprintf("log%d", logCounter)
702
- cl.Include = []string{"http.log.access." + val.name}
703
- val.log = cl
704
- logCounter++
705
- h.State["logCounter"] = logCounter
771
}
772
configValues = append(configValues, ConfigValue{
773
Class: "custom_log",