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()) | 		tpe, _ := response.Typify(rrw.Msg, time.Now().UTC()) | ||||||
| 		class := response.Classify(tpe) | 		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) | 			rep := replacer.New(r, rrw, CommonLogEmptyValue) | ||||||
| 			rule.Log.Println(rep.Replace(rule.Format)) | 			rule.Log.Println(rep.Replace(rule.Format)) | ||||||
| 		} | 		} | ||||||
| @@ -71,7 +73,7 @@ func (l Logger) Name() string { return "log" } | |||||||
| // Rule configures the logging plugin. | // Rule configures the logging plugin. | ||||||
| type Rule struct { | type Rule struct { | ||||||
| 	NameScope string | 	NameScope string | ||||||
| 	Class     response.Class | 	Class     map[response.Class]bool | ||||||
| 	Format    string | 	Format    string | ||||||
| 	Log       *log.Logger | 	Log       *log.Logger | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ func TestLoggedStatus(t *testing.T) { | |||||||
| 		NameScope: ".", | 		NameScope: ".", | ||||||
| 		Format:    DefaultLogFormat, | 		Format:    DefaultLogFormat, | ||||||
| 		Log:       log.New(&f, "", 0), | 		Log:       log.New(&f, "", 0), | ||||||
|  | 		Class:     map[response.Class]bool{response.All: true}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	logger := Logger{ | 	logger := Logger{ | ||||||
| @@ -50,7 +51,7 @@ func TestLoggedClassDenial(t *testing.T) { | |||||||
| 		NameScope: ".", | 		NameScope: ".", | ||||||
| 		Format:    DefaultLogFormat, | 		Format:    DefaultLogFormat, | ||||||
| 		Log:       log.New(&f, "", 0), | 		Log:       log.New(&f, "", 0), | ||||||
| 		Class:     response.Denial, | 		Class:     map[response.Class]bool{response.Denial: true}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	logger := Logger{ | 	logger := Logger{ | ||||||
| @@ -78,7 +79,7 @@ func TestLoggedClassError(t *testing.T) { | |||||||
| 		NameScope: ".", | 		NameScope: ".", | ||||||
| 		Format:    DefaultLogFormat, | 		Format:    DefaultLogFormat, | ||||||
| 		Log:       log.New(&f, "", 0), | 		Log:       log.New(&f, "", 0), | ||||||
| 		Class:     response.Error, | 		Class:     map[response.Class]bool{response.Error: true}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	logger := Logger{ | 	logger := Logger{ | ||||||
|   | |||||||
| @@ -52,11 +52,13 @@ func logParse(c *caddy.Controller) ([]Rule, error) { | |||||||
| 			rules = append(rules, Rule{ | 			rules = append(rules, Rule{ | ||||||
| 				NameScope: ".", | 				NameScope: ".", | ||||||
| 				Format:    DefaultLogFormat, | 				Format:    DefaultLogFormat, | ||||||
|  | 				Class:     make(map[response.Class]bool), | ||||||
| 			}) | 			}) | ||||||
| 		} else if len(args) == 1 { | 		} else if len(args) == 1 { | ||||||
| 			rules = append(rules, Rule{ | 			rules = append(rules, Rule{ | ||||||
| 				NameScope: dns.Fqdn(args[0]), | 				NameScope: dns.Fqdn(args[0]), | ||||||
| 				Format:    DefaultLogFormat, | 				Format:    DefaultLogFormat, | ||||||
|  | 				Class:     make(map[response.Class]bool), | ||||||
| 			}) | 			}) | ||||||
| 		} else { | 		} else { | ||||||
| 			// Name scope, and maybe a format specified | 			// Name scope, and maybe a format specified | ||||||
| @@ -74,28 +76,33 @@ func logParse(c *caddy.Controller) ([]Rule, error) { | |||||||
| 			rules = append(rules, Rule{ | 			rules = append(rules, Rule{ | ||||||
| 				NameScope: dns.Fqdn(args[0]), | 				NameScope: dns.Fqdn(args[0]), | ||||||
| 				Format:    format, | 				Format:    format, | ||||||
|  | 				Class:     make(map[response.Class]bool), | ||||||
| 			}) | 			}) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Class refinements in an extra block. | 		// Class refinements in an extra block. | ||||||
| 		for c.NextBlock() { | 		for c.NextBlock() { | ||||||
| 			switch c.Val() { | 			switch c.Val() { | ||||||
| 			// class followed by all, denial, error or success. | 			// class followed by combinations of all, denial, error and success. | ||||||
| 			case "class": | 			case "class": | ||||||
| 				classes := c.RemainingArgs() | 				classes := c.RemainingArgs() | ||||||
| 				if len(classes) == 0 { | 				if len(classes) == 0 { | ||||||
| 					return nil, c.ArgErr() | 					return nil, c.ArgErr() | ||||||
| 				} | 				} | ||||||
| 				cls, err := response.ClassFromString(classes[0]) | 				for _, c := range classes { | ||||||
| 				if err != nil { | 					cls, err := response.ClassFromString(c) | ||||||
| 					return nil, err | 					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: | 			default: | ||||||
| 				return nil, c.ArgErr() | 				return nil, c.ArgErr() | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		if len(rules[len(rules)-1].Class) == 0 { | ||||||
|  | 			rules[len(rules)-1].Class[response.All] = true | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return rules, nil | 	return rules, nil | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package log | package log | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/coredns/coredns/plugin/pkg/response" | 	"github.com/coredns/coredns/plugin/pkg/response" | ||||||
| @@ -17,34 +18,42 @@ func TestLogParse(t *testing.T) { | |||||||
| 		{`log`, false, []Rule{{ | 		{`log`, false, []Rule{{ | ||||||
| 			NameScope: ".", | 			NameScope: ".", | ||||||
| 			Format:    DefaultLogFormat, | 			Format:    DefaultLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org`, false, []Rule{{ | 		{`log example.org`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    DefaultLogFormat, | 			Format:    DefaultLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org. {common}`, false, []Rule{{ | 		{`log example.org. {common}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    CommonLogFormat, | 			Format:    CommonLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org {combined}`, false, []Rule{{ | 		{`log example.org {combined}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    CombinedLogFormat, | 			Format:    CombinedLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org. | 		{`log example.org. | ||||||
| 		log example.net {combined}`, false, []Rule{{ | 		log example.net {combined}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    DefaultLogFormat, | 			Format:    DefaultLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}, { | 		}, { | ||||||
| 			NameScope: "example.net.", | 			NameScope: "example.net.", | ||||||
| 			Format:    CombinedLogFormat, | 			Format:    CombinedLogFormat, | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org {host} | 		{`log example.org {host} | ||||||
| 			  log example.org {when}`, false, []Rule{{ | 			  log example.org {when}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    "{host}", | 			Format:    "{host}", | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}, { | 		}, { | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    "{when}", | 			Format:    "{when}", | ||||||
|  | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
|  |  | ||||||
| 		{`log example.org { | 		{`log example.org { | ||||||
| @@ -52,22 +61,49 @@ func TestLogParse(t *testing.T) { | |||||||
| 			}`, false, []Rule{{ | 			}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    CommonLogFormat, | 			Format:    CommonLogFormat, | ||||||
| 			Class:     response.All, | 			Class:     map[response.Class]bool{response.All: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log example.org { | 		{`log example.org { | ||||||
| 			class denial | 			class denial | ||||||
| 		}`, false, []Rule{{ | 		}`, false, []Rule{{ | ||||||
| 			NameScope: "example.org.", | 			NameScope: "example.org.", | ||||||
| 			Format:    CommonLogFormat, | 			Format:    CommonLogFormat, | ||||||
| 			Class:     response.Denial, | 			Class:     map[response.Class]bool{response.Denial: true}, | ||||||
| 		}}}, | 		}}}, | ||||||
| 		{`log { | 		{`log { | ||||||
| 			class denial | 			class denial | ||||||
| 		}`, false, []Rule{{ | 		}`, false, []Rule{{ | ||||||
| 			NameScope: ".", | 			NameScope: ".", | ||||||
| 			Format:    CommonLogFormat, | 			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 { | 	for i, test := range tests { | ||||||
| 		c := caddy.NewTestController("dns", test.inputLogRules) | 		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) | 					i, j, test.inputLogRules, test.expectedLogRules[j].Format, actualLogRule.Format) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if actualLogRule.Class != test.expectedLogRules[j].Class { | 			if !reflect.DeepEqual(actualLogRule.Class, test.expectedLogRules[j].Class) { | ||||||
| 				t.Errorf("Test %d expected %dth LogRule Class to be  %s  , but got %s", | 				t.Errorf("Test %d expected %dth LogRule Class to be  %v  , but got %v", | ||||||
| 					i, j, test.expectedLogRules[j].Class, actualLogRule.Class) | 					i, j, test.expectedLogRules[j].Class, actualLogRule.Class) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user