mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-30 17:53:21 -04:00 
			
		
		
		
	plugin/log: allow various combinations of classes of responses (#1664)
This allows to log responses of different classes, for example, denial and error.
This commit is contained in:
		
				
					committed by
					
						 Miek Gieben
						Miek Gieben
					
				
			
			
				
	
			
			
			
						parent
						
							a20b4fe2de
						
					
				
				
					commit
					ccfe691b95
				
			| @@ -54,7 +54,9 @@ func (l Logger) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) | ||||
|  | ||||
| 		tpe, _ := response.Typify(rrw.Msg, time.Now().UTC()) | ||||
| 		class := response.Classify(tpe) | ||||
| 		if rule.Class == response.All || rule.Class == class { | ||||
| 		// If we don't set up a class in config, the default "all" will be added | ||||
| 		// and we shouldn't have an empty rule.Class. | ||||
| 		if rule.Class[response.All] || rule.Class[class] { | ||||
| 			rep := replacer.New(r, rrw, CommonLogEmptyValue) | ||||
| 			rule.Log.Println(rep.Replace(rule.Format)) | ||||
| 		} | ||||
| @@ -71,7 +73,7 @@ func (l Logger) Name() string { return "log" } | ||||
| // Rule configures the logging plugin. | ||||
| type Rule struct { | ||||
| 	NameScope string | ||||
| 	Class     response.Class | ||||
| 	Class     map[response.Class]bool | ||||
| 	Format    string | ||||
| 	Log       *log.Logger | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,7 @@ func TestLoggedStatus(t *testing.T) { | ||||
| 		NameScope: ".", | ||||
| 		Format:    DefaultLogFormat, | ||||
| 		Log:       log.New(&f, "", 0), | ||||
| 		Class:     map[response.Class]bool{response.All: true}, | ||||
| 	} | ||||
|  | ||||
| 	logger := Logger{ | ||||
| @@ -50,7 +51,7 @@ func TestLoggedClassDenial(t *testing.T) { | ||||
| 		NameScope: ".", | ||||
| 		Format:    DefaultLogFormat, | ||||
| 		Log:       log.New(&f, "", 0), | ||||
| 		Class:     response.Denial, | ||||
| 		Class:     map[response.Class]bool{response.Denial: true}, | ||||
| 	} | ||||
|  | ||||
| 	logger := Logger{ | ||||
| @@ -78,7 +79,7 @@ func TestLoggedClassError(t *testing.T) { | ||||
| 		NameScope: ".", | ||||
| 		Format:    DefaultLogFormat, | ||||
| 		Log:       log.New(&f, "", 0), | ||||
| 		Class:     response.Error, | ||||
| 		Class:     map[response.Class]bool{response.Error: true}, | ||||
| 	} | ||||
|  | ||||
| 	logger := Logger{ | ||||
|   | ||||
| @@ -52,11 +52,13 @@ func logParse(c *caddy.Controller) ([]Rule, error) { | ||||
| 			rules = append(rules, Rule{ | ||||
| 				NameScope: ".", | ||||
| 				Format:    DefaultLogFormat, | ||||
| 				Class:     make(map[response.Class]bool), | ||||
| 			}) | ||||
| 		} else if len(args) == 1 { | ||||
| 			rules = append(rules, Rule{ | ||||
| 				NameScope: dns.Fqdn(args[0]), | ||||
| 				Format:    DefaultLogFormat, | ||||
| 				Class:     make(map[response.Class]bool), | ||||
| 			}) | ||||
| 		} else { | ||||
| 			// Name scope, and maybe a format specified | ||||
| @@ -74,28 +76,33 @@ func logParse(c *caddy.Controller) ([]Rule, error) { | ||||
| 			rules = append(rules, Rule{ | ||||
| 				NameScope: dns.Fqdn(args[0]), | ||||
| 				Format:    format, | ||||
| 				Class:     make(map[response.Class]bool), | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		// Class refinements in an extra block. | ||||
| 		for c.NextBlock() { | ||||
| 			switch c.Val() { | ||||
| 			// class followed by all, denial, error or success. | ||||
| 			// class followed by combinations of all, denial, error and success. | ||||
| 			case "class": | ||||
| 				classes := c.RemainingArgs() | ||||
| 				if len(classes) == 0 { | ||||
| 					return nil, c.ArgErr() | ||||
| 				} | ||||
| 				cls, err := response.ClassFromString(classes[0]) | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				for _, c := range classes { | ||||
| 					cls, err := response.ClassFromString(c) | ||||
| 					if err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 					rules[len(rules)-1].Class[cls] = true | ||||
| 				} | ||||
| 				// update class and the last added Rule (bit icky) | ||||
| 				rules[len(rules)-1].Class = cls | ||||
| 			default: | ||||
| 				return nil, c.ArgErr() | ||||
| 			} | ||||
| 		} | ||||
| 		if len(rules[len(rules)-1].Class) == 0 { | ||||
| 			rules[len(rules)-1].Class[response.All] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return rules, nil | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package log | ||||
|  | ||||
| import ( | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/coredns/coredns/plugin/pkg/response" | ||||
| @@ -17,34 +18,42 @@ func TestLogParse(t *testing.T) { | ||||
| 		{`log`, false, []Rule{{ | ||||
| 			NameScope: ".", | ||||
| 			Format:    DefaultLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    DefaultLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org. {common}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org {combined}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    CombinedLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org. | ||||
| 		log example.net {combined}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    DefaultLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}, { | ||||
| 			NameScope: "example.net.", | ||||
| 			Format:    CombinedLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org {host} | ||||
| 			  log example.org {when}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    "{host}", | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}, { | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    "{when}", | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
|  | ||||
| 		{`log example.org { | ||||
| @@ -52,22 +61,49 @@ func TestLogParse(t *testing.T) { | ||||
| 			}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     response.All, | ||||
| 			Class:     map[response.Class]bool{response.All: true}, | ||||
| 		}}}, | ||||
| 		{`log example.org { | ||||
| 			class denial | ||||
| 		}`, false, []Rule{{ | ||||
| 			NameScope: "example.org.", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     response.Denial, | ||||
| 			Class:     map[response.Class]bool{response.Denial: true}, | ||||
| 		}}}, | ||||
| 		{`log { | ||||
| 			class denial | ||||
| 		}`, false, []Rule{{ | ||||
| 			NameScope: ".", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     response.Denial, | ||||
| 			Class:     map[response.Class]bool{response.Denial: true}, | ||||
| 		}}}, | ||||
| 		{`log { | ||||
| 			class denial error | ||||
| 		}`, false, []Rule{{ | ||||
| 			NameScope: ".", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.Denial: true, response.Error: true}, | ||||
| 		}}}, | ||||
| 		{`log { | ||||
| 			class denial | ||||
| 			class error | ||||
| 		}`, false, []Rule{{ | ||||
| 			NameScope: ".", | ||||
| 			Format:    CommonLogFormat, | ||||
| 			Class:     map[response.Class]bool{response.Denial: true, response.Error: true}, | ||||
| 		}}}, | ||||
| 		{`log { | ||||
| 			class abracadabra | ||||
| 		}`, true, []Rule{ | ||||
| 		}}, | ||||
| 		{`log { | ||||
| 			class | ||||
| 		}`, true, []Rule{ | ||||
| 		}}, | ||||
| 		{`log { | ||||
| 			unknown | ||||
| 		}`, true, []Rule{ | ||||
| 		}}, | ||||
| 	} | ||||
| 	for i, test := range tests { | ||||
| 		c := caddy.NewTestController("dns", test.inputLogRules) | ||||
| @@ -95,8 +131,8 @@ func TestLogParse(t *testing.T) { | ||||
| 					i, j, test.inputLogRules, test.expectedLogRules[j].Format, actualLogRule.Format) | ||||
| 			} | ||||
|  | ||||
| 			if actualLogRule.Class != test.expectedLogRules[j].Class { | ||||
| 				t.Errorf("Test %d expected %dth LogRule Class to be  %s  , but got %s", | ||||
| 			if !reflect.DeepEqual(actualLogRule.Class, test.expectedLogRules[j].Class) { | ||||
| 				t.Errorf("Test %d expected %dth LogRule Class to be  %v  , but got %v", | ||||
| 					i, j, test.expectedLogRules[j].Class, actualLogRule.Class) | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user