...

Source file src/github.com/prometheus/alertmanager/dispatch/route.go

Documentation: github.com/prometheus/alertmanager/dispatch

     1  // Copyright 2015 Prometheus Team
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package dispatch
    15  
    16  import (
    17  	"encoding/json"
    18  	"fmt"
    19  	"sort"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/prometheus/common/model"
    24  
    25  	"github.com/prometheus/alertmanager/config"
    26  	"github.com/prometheus/alertmanager/pkg/labels"
    27  )
    28  
    29  // DefaultRouteOpts are the defaulting routing options which apply
    30  // to the root route of a routing tree.
    31  var DefaultRouteOpts = RouteOpts{
    32  	GroupWait:         30 * time.Second,
    33  	GroupInterval:     5 * time.Minute,
    34  	RepeatInterval:    4 * time.Hour,
    35  	GroupBy:           map[model.LabelName]struct{}{},
    36  	GroupByAll:        false,
    37  	MuteTimeIntervals: []string{},
    38  }
    39  
    40  // A Route is a node that contains definitions of how to handle alerts.
    41  type Route struct {
    42  	parent *Route
    43  
    44  	// The configuration parameters for matches of this route.
    45  	RouteOpts RouteOpts
    46  
    47  	// Matchers an alert has to fulfill to match
    48  	// this route.
    49  	Matchers labels.Matchers
    50  
    51  	// If true, an alert matches further routes on the same level.
    52  	Continue bool
    53  
    54  	// Children routes of this route.
    55  	Routes []*Route
    56  }
    57  
    58  // NewRoute returns a new route.
    59  func NewRoute(cr *config.Route, parent *Route) *Route {
    60  	// Create default and overwrite with configured settings.
    61  	opts := DefaultRouteOpts
    62  	if parent != nil {
    63  		opts = parent.RouteOpts
    64  	}
    65  
    66  	if cr.Receiver != "" {
    67  		opts.Receiver = cr.Receiver
    68  	}
    69  
    70  	if cr.GroupBy != nil {
    71  		opts.GroupBy = map[model.LabelName]struct{}{}
    72  		for _, ln := range cr.GroupBy {
    73  			opts.GroupBy[ln] = struct{}{}
    74  		}
    75  		opts.GroupByAll = false
    76  	} else {
    77  		if cr.GroupByAll {
    78  			opts.GroupByAll = cr.GroupByAll
    79  		}
    80  	}
    81  
    82  	if cr.GroupWait != nil {
    83  		opts.GroupWait = time.Duration(*cr.GroupWait)
    84  	}
    85  	if cr.GroupInterval != nil {
    86  		opts.GroupInterval = time.Duration(*cr.GroupInterval)
    87  	}
    88  	if cr.RepeatInterval != nil {
    89  		opts.RepeatInterval = time.Duration(*cr.RepeatInterval)
    90  	}
    91  
    92  	// Build matchers.
    93  	var matchers labels.Matchers
    94  
    95  	// cr.Match will be deprecated. This for loop appends matchers.
    96  	for ln, lv := range cr.Match {
    97  		matcher, err := labels.NewMatcher(labels.MatchEqual, ln, lv)
    98  		if err != nil {
    99  			// This error must not happen because the config already validates the yaml.
   100  			panic(err)
   101  		}
   102  		matchers = append(matchers, matcher)
   103  	}
   104  
   105  	// cr.MatchRE will be deprecated. This for loop appends regex matchers.
   106  	for ln, lv := range cr.MatchRE {
   107  		matcher, err := labels.NewMatcher(labels.MatchRegexp, ln, lv.String())
   108  		if err != nil {
   109  			// This error must not happen because the config already validates the yaml.
   110  			panic(err)
   111  		}
   112  		matchers = append(matchers, matcher)
   113  	}
   114  
   115  	// We append the new-style matchers. This can be simplified once the deprecated matcher syntax is removed.
   116  	matchers = append(matchers, cr.Matchers...)
   117  
   118  	sort.Sort(matchers)
   119  
   120  	opts.MuteTimeIntervals = cr.MuteTimeIntervals
   121  	opts.ActiveTimeIntervals = cr.ActiveTimeIntervals
   122  
   123  	route := &Route{
   124  		parent:    parent,
   125  		RouteOpts: opts,
   126  		Matchers:  matchers,
   127  		Continue:  cr.Continue,
   128  	}
   129  
   130  	route.Routes = NewRoutes(cr.Routes, route)
   131  
   132  	return route
   133  }
   134  
   135  // NewRoutes returns a slice of routes.
   136  func NewRoutes(croutes []*config.Route, parent *Route) []*Route {
   137  	res := []*Route{}
   138  	for _, cr := range croutes {
   139  		res = append(res, NewRoute(cr, parent))
   140  	}
   141  	return res
   142  }
   143  
   144  // Match does a depth-first left-to-right search through the route tree
   145  // and returns the matching routing nodes.
   146  func (r *Route) Match(lset model.LabelSet) []*Route {
   147  	if !r.Matchers.Matches(lset) {
   148  		return nil
   149  	}
   150  
   151  	var all []*Route
   152  
   153  	for _, cr := range r.Routes {
   154  		matches := cr.Match(lset)
   155  
   156  		all = append(all, matches...)
   157  
   158  		if matches != nil && !cr.Continue {
   159  			break
   160  		}
   161  	}
   162  
   163  	// If no child nodes were matches, the current node itself is a match.
   164  	if len(all) == 0 {
   165  		all = append(all, r)
   166  	}
   167  
   168  	return all
   169  }
   170  
   171  // Key returns a key for the route. It does not uniquely identify the route in general.
   172  func (r *Route) Key() string {
   173  	b := strings.Builder{}
   174  
   175  	if r.parent != nil {
   176  		b.WriteString(r.parent.Key())
   177  		b.WriteRune('/')
   178  	}
   179  	b.WriteString(r.Matchers.String())
   180  	return b.String()
   181  }
   182  
   183  // Walk traverses the route tree in depth-first order.
   184  func (r *Route) Walk(visit func(*Route)) {
   185  	visit(r)
   186  	for i := range r.Routes {
   187  		r.Routes[i].Walk(visit)
   188  	}
   189  }
   190  
   191  // RouteOpts holds various routing options necessary for processing alerts
   192  // that match a given route.
   193  type RouteOpts struct {
   194  	// The identifier of the associated notification configuration.
   195  	Receiver string
   196  
   197  	// What labels to group alerts by for notifications.
   198  	GroupBy map[model.LabelName]struct{}
   199  
   200  	// Use all alert labels to group.
   201  	GroupByAll bool
   202  
   203  	// How long to wait to group matching alerts before sending
   204  	// a notification.
   205  	GroupWait      time.Duration
   206  	GroupInterval  time.Duration
   207  	RepeatInterval time.Duration
   208  
   209  	// A list of time intervals for which the route is muted.
   210  	MuteTimeIntervals []string
   211  
   212  	// A list of time intervals for which the route is active.
   213  	ActiveTimeIntervals []string
   214  }
   215  
   216  func (ro *RouteOpts) String() string {
   217  	var labels []model.LabelName
   218  	for ln := range ro.GroupBy {
   219  		labels = append(labels, ln)
   220  	}
   221  	return fmt.Sprintf("<RouteOpts send_to:%q group_by:%q group_by_all:%t timers:%q|%q>",
   222  		ro.Receiver, labels, ro.GroupByAll, ro.GroupWait, ro.GroupInterval)
   223  }
   224  
   225  // MarshalJSON returns a JSON representation of the routing options.
   226  func (ro *RouteOpts) MarshalJSON() ([]byte, error) {
   227  	v := struct {
   228  		Receiver       string           `json:"receiver"`
   229  		GroupBy        model.LabelNames `json:"groupBy"`
   230  		GroupByAll     bool             `json:"groupByAll"`
   231  		GroupWait      time.Duration    `json:"groupWait"`
   232  		GroupInterval  time.Duration    `json:"groupInterval"`
   233  		RepeatInterval time.Duration    `json:"repeatInterval"`
   234  	}{
   235  		Receiver:       ro.Receiver,
   236  		GroupByAll:     ro.GroupByAll,
   237  		GroupWait:      ro.GroupWait,
   238  		GroupInterval:  ro.GroupInterval,
   239  		RepeatInterval: ro.RepeatInterval,
   240  	}
   241  	for ln := range ro.GroupBy {
   242  		v.GroupBy = append(v.GroupBy, ln)
   243  	}
   244  
   245  	return json.Marshal(&v)
   246  }
   247  

View as plain text