// Create a new AlertNode which caches the most recent item and exposes it over the HTTP API. func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode, l *log.Logger) (an *AlertNode, err error) { an = &AlertNode{ node: node{Node: n, et: et, logger: l}, a: n, } an.node.runF = an.runAlert // Create buffer pool for the templates an.bufPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) }, } // Parse templates an.idTmpl, err = text.New("id").Parse(n.Id) if err != nil { return nil, err } an.messageTmpl, err = text.New("message").Parse(n.Message) if err != nil { return nil, err } an.detailsTmpl, err = html.New("details").Funcs(html.FuncMap{ "json": func(v interface{}) html.JS { tmpBuffer := an.bufPool.Get().(*bytes.Buffer) defer func() { tmpBuffer.Reset() an.bufPool.Put(tmpBuffer) }() json.NewEncoder(tmpBuffer).Encode(v) return html.JS(tmpBuffer.String()) }, }).Parse(n.Details) if err != nil { return nil, err } // Construct alert handlers an.handlers = make([]AlertHandler, 0) for _, post := range n.PostHandlers { post := post an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePost(post, ad) }) } for _, email := range n.EmailHandlers { email := email an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(email, ad) }) } if len(n.EmailHandlers) == 0 && (et.tm.SMTPService != nil && et.tm.SMTPService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(&pipeline.EmailHandler{}, ad) }) } // If email has been configured with state changes only set it. if et.tm.SMTPService != nil && et.tm.SMTPService.Global() && et.tm.SMTPService.StateChangesOnly() { n.IsStateChangesOnly = true } for _, exec := range n.ExecHandlers { exec := exec an.handlers = append(an.handlers, func(ad *AlertData) { an.handleExec(exec, ad) }) } for _, log := range n.LogHandlers { log := log if !filepath.IsAbs(log.FilePath) { return nil, fmt.Errorf("alert log path must be absolute: %s is not absolute", log.FilePath) } an.handlers = append(an.handlers, func(ad *AlertData) { an.handleLog(log, ad) }) } for _, vo := range n.VictorOpsHandlers { vo := vo an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(vo, ad) }) } if len(n.VictorOpsHandlers) == 0 && (et.tm.VictorOpsService != nil && et.tm.VictorOpsService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(&pipeline.VictorOpsHandler{}, ad) }) } for _, pd := range n.PagerDutyHandlers { pd := pd an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(pd, ad) }) } if len(n.PagerDutyHandlers) == 0 && (et.tm.PagerDutyService != nil && et.tm.PagerDutyService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(&pipeline.PagerDutyHandler{}, ad) }) } for _, sensu := range n.SensuHandlers { sensu := sensu an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSensu(sensu, ad) }) } for _, slack := range n.SlackHandlers { slack := slack an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(slack, ad) }) } if len(n.SlackHandlers) == 0 && (et.tm.SlackService != nil && et.tm.SlackService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(&pipeline.SlackHandler{}, ad) }) } // If slack has been configured with state changes only set it. if et.tm.SlackService != nil && et.tm.SlackService.Global() && et.tm.SlackService.StateChangesOnly() { n.IsStateChangesOnly = true } for _, telegram := range n.TelegramHandlers { telegram := telegram an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTelegram(telegram, ad) }) } if len(n.TelegramHandlers) == 0 && (et.tm.TelegramService != nil && et.tm.TelegramService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTelegram(&pipeline.TelegramHandler{}, ad) }) } // If telegram has been configured with state changes only set it. if et.tm.TelegramService != nil && et.tm.TelegramService.Global() && et.tm.TelegramService.StateChangesOnly() { n.IsStateChangesOnly = true } for _, hipchat := range n.HipChatHandlers { hipchat := hipchat an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(hipchat, ad) }) } if len(n.HipChatHandlers) == 0 && (et.tm.HipChatService != nil && et.tm.HipChatService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(&pipeline.HipChatHandler{}, ad) }) } // If HipChat has been configured with state changes only set it. if et.tm.HipChatService != nil && et.tm.HipChatService.Global() && et.tm.HipChatService.StateChangesOnly() { n.IsStateChangesOnly = true } for _, alerta := range n.AlertaHandlers { // Validate alerta templates rtmpl, err := text.New("resource").Parse(alerta.Resource) if err != nil { return nil, err } evtmpl, err := text.New("event").Parse(alerta.Event) if err != nil { return nil, err } etmpl, err := text.New("environment").Parse(alerta.Environment) if err != nil { return nil, err } gtmpl, err := text.New("group").Parse(alerta.Group) if err != nil { return nil, err } vtmpl, err := text.New("value").Parse(alerta.Value) if err != nil { return nil, err } ai := alertaHandler{ AlertaHandler: alerta, resourceTmpl: rtmpl, eventTmpl: evtmpl, environmentTmpl: etmpl, groupTmpl: gtmpl, valueTmpl: vtmpl, } an.handlers = append(an.handlers, func(ad *AlertData) { an.handleAlerta(ai, ad) }) } for _, og := range n.OpsGenieHandlers { og := og an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(og, ad) }) } if len(n.OpsGenieHandlers) == 0 && (et.tm.OpsGenieService != nil && et.tm.OpsGenieService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(&pipeline.OpsGenieHandler{}, ad) }) } for _, talk := range n.TalkHandlers { talk := talk an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTalk(talk, ad) }) } // Parse level expressions an.levels = make([]stateful.Expression, CritAlert+1) an.scopePools = make([]stateful.ScopePool, CritAlert+1) if n.Info != nil { statefulExpression, expressionCompileError := stateful.NewExpression(n.Info.Expression) if expressionCompileError != nil { return nil, fmt.Errorf("Failed to compile stateful expression for info: %s", expressionCompileError) } an.levels[InfoAlert] = statefulExpression an.scopePools[InfoAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Info.Expression)) } if n.Warn != nil { statefulExpression, expressionCompileError := stateful.NewExpression(n.Warn.Expression) if expressionCompileError != nil { return nil, fmt.Errorf("Failed to compile stateful expression for warn: %s", expressionCompileError) } an.levels[WarnAlert] = statefulExpression an.scopePools[WarnAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Warn.Expression)) } if n.Crit != nil { statefulExpression, expressionCompileError := stateful.NewExpression(n.Crit.Expression) if expressionCompileError != nil { return nil, fmt.Errorf("Failed to compile stateful expression for crit: %s", expressionCompileError) } an.levels[CritAlert] = statefulExpression an.scopePools[CritAlert] = stateful.NewScopePool(stateful.FindReferenceVariables(n.Crit.Expression)) } // Setup states if n.History < 2 { n.History = 2 } an.states = make(map[models.GroupID]*alertState) // Configure flapping if n.UseFlapping { if n.FlapLow > 1 || n.FlapHigh > 1 { return nil, errors.New("alert flap thresholds are percentages and should be between 0 and 1") } } return }
// Create a new AlertNode which caches the most recent item and exposes it over the HTTP API. func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode) (an *AlertNode, err error) { an = &AlertNode{ node: node{Node: n, et: et}, a: n, } an.node.runF = an.runAlert // Parse templates tmpl, err := template.New("id").Parse(n.Id) if err != nil { return nil, err } an.idTmpl = tmpl tmpl, err = template.New("message").Parse(n.Message) if err != nil { return nil, err } an.messageTmpl = tmpl // Construct alert handlers an.handlers = make([]AlertHandler, 0) for _, post := range n.PostHandlers { post := post an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePost(post, ad) }) } for _, email := range n.EmailHandlers { email := email an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(email, ad) }) } if len(n.EmailHandlers) == 0 && (et.tm.SMTPService != nil && et.tm.SMTPService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(&pipeline.EmailHandler{}, ad) }) } // If email has been configured globally only send state changes. if et.tm.SMTPService != nil && et.tm.SMTPService.Global() { n.IsStateChangesOnly = true } for _, exec := range n.ExecHandlers { exec := exec an.handlers = append(an.handlers, func(ad *AlertData) { an.handleExec(exec, ad) }) } for _, log := range n.LogHandlers { log := log if !path.IsAbs(log.FilePath) { return nil, fmt.Errorf("alert log path must be absolute: %s is not absolute", log.FilePath) } an.handlers = append(an.handlers, func(ad *AlertData) { an.handleLog(log, ad) }) } for _, vo := range n.VictorOpsHandlers { vo := vo an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(vo, ad) }) } if len(n.VictorOpsHandlers) == 0 && (et.tm.VictorOpsService != nil && et.tm.VictorOpsService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(&pipeline.VictorOpsHandler{}, ad) }) } for _, pd := range n.PagerDutyHandlers { pd := pd an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(pd, ad) }) } if len(n.PagerDutyHandlers) == 0 && (et.tm.PagerDutyService != nil && et.tm.PagerDutyService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(&pipeline.PagerDutyHandler{}, ad) }) } for _, slack := range n.SlackHandlers { slack := slack an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(slack, ad) }) } if len(n.SlackHandlers) == 0 && (et.tm.SlackService != nil && et.tm.SlackService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(&pipeline.SlackHandler{}, ad) }) } // If slack has been configured globally only send state changes. if et.tm.SlackService != nil && et.tm.SlackService.Global() { n.IsStateChangesOnly = true } for _, hipchat := range n.HipChatHandlers { hipchat := hipchat an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(hipchat, ad) }) } if len(n.HipChatHandlers) == 0 && (et.tm.HipChatService != nil && et.tm.HipChatService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(&pipeline.HipChatHandler{}, ad) }) } // If HipChat has been configured globally only send state changes. if et.tm.HipChatService != nil && et.tm.HipChatService.Global() { n.IsStateChangesOnly = true } for _, og := range n.OpsGenieHandlers { og := og an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(og, ad) }) } if len(n.OpsGenieHandlers) == 0 && (et.tm.OpsGenieService != nil && et.tm.OpsGenieService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(&pipeline.OpsGenieHandler{}, ad) }) } // Parse level expressions an.levels = make([]*tick.StatefulExpr, CritAlert+1) if n.Info != nil { an.levels[InfoAlert] = tick.NewStatefulExpr(n.Info) } if n.Warn != nil { an.levels[WarnAlert] = tick.NewStatefulExpr(n.Warn) } if n.Crit != nil { an.levels[CritAlert] = tick.NewStatefulExpr(n.Crit) } // Setup states if n.History < 2 { n.History = 2 } an.states = make(map[models.GroupID]*alertState) // Configure flapping if n.UseFlapping { if n.FlapLow > 1 || n.FlapHigh > 1 { return nil, errors.New("alert flap thresholds are percentages and should be between 0 and 1") } } return }
// Create a new AlertNode which caches the most recent item and exposes it over the HTTP API. func newAlertNode(et *ExecutingTask, n *pipeline.AlertNode, l *log.Logger) (an *AlertNode, err error) { an = &AlertNode{ node: node{Node: n, et: et, logger: l}, a: n, } an.node.runF = an.runAlert // Parse templates an.idTmpl, err = text.New("id").Parse(n.Id) if err != nil { return nil, err } an.messageTmpl, err = text.New("message").Parse(n.Message) if err != nil { return nil, err } an.detailsTmpl, err = html.New("details").Funcs(html.FuncMap{ "json": func(v interface{}) html.JS { a, _ := json.Marshal(v) return html.JS(a) }, }).Parse(n.Details) if err != nil { return nil, err } // Construct alert handlers an.handlers = make([]AlertHandler, 0) for _, post := range n.PostHandlers { post := post an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePost(post, ad) }) } for _, email := range n.EmailHandlers { email := email an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(email, ad) }) } if len(n.EmailHandlers) == 0 && (et.tm.SMTPService != nil && et.tm.SMTPService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleEmail(&pipeline.EmailHandler{}, ad) }) } // If email has been configured globally only send state changes. if et.tm.SMTPService != nil && et.tm.SMTPService.Global() { n.IsStateChangesOnly = true } for _, exec := range n.ExecHandlers { exec := exec an.handlers = append(an.handlers, func(ad *AlertData) { an.handleExec(exec, ad) }) } for _, log := range n.LogHandlers { log := log if !path.IsAbs(log.FilePath) { return nil, fmt.Errorf("alert log path must be absolute: %s is not absolute", log.FilePath) } an.handlers = append(an.handlers, func(ad *AlertData) { an.handleLog(log, ad) }) } for _, vo := range n.VictorOpsHandlers { vo := vo an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(vo, ad) }) } if len(n.VictorOpsHandlers) == 0 && (et.tm.VictorOpsService != nil && et.tm.VictorOpsService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleVictorOps(&pipeline.VictorOpsHandler{}, ad) }) } for _, pd := range n.PagerDutyHandlers { pd := pd an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(pd, ad) }) } if len(n.PagerDutyHandlers) == 0 && (et.tm.PagerDutyService != nil && et.tm.PagerDutyService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handlePagerDuty(&pipeline.PagerDutyHandler{}, ad) }) } for _, sensu := range n.SensuHandlers { sensu := sensu an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSensu(sensu, ad) }) } for _, slack := range n.SlackHandlers { slack := slack an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(slack, ad) }) } if len(n.SlackHandlers) == 0 && (et.tm.SlackService != nil && et.tm.SlackService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleSlack(&pipeline.SlackHandler{}, ad) }) } // If slack has been configured globally only send state changes. if et.tm.SlackService != nil && et.tm.SlackService.Global() { n.IsStateChangesOnly = true } for _, hipchat := range n.HipChatHandlers { hipchat := hipchat an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(hipchat, ad) }) } if len(n.HipChatHandlers) == 0 && (et.tm.HipChatService != nil && et.tm.HipChatService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleHipChat(&pipeline.HipChatHandler{}, ad) }) } // If HipChat has been configured globally only send state changes. if et.tm.HipChatService != nil && et.tm.HipChatService.Global() { n.IsStateChangesOnly = true } for _, alerta := range n.AlertaHandlers { // Validate alerta templates rtmpl, err := text.New("resource").Parse(alerta.Resource) if err != nil { return nil, err } gtmpl, err := text.New("group").Parse(alerta.Group) if err != nil { return nil, err } vtmpl, err := text.New("value").Parse(alerta.Value) if err != nil { return nil, err } ai := alertaHandler{ AlertaHandler: alerta, resourceTmpl: rtmpl, groupTmpl: gtmpl, valueTmpl: vtmpl, } an.handlers = append(an.handlers, func(ad *AlertData) { an.handleAlerta(ai, ad) }) } for _, og := range n.OpsGenieHandlers { og := og an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(og, ad) }) } if len(n.OpsGenieHandlers) == 0 && (et.tm.OpsGenieService != nil && et.tm.OpsGenieService.Global()) { an.handlers = append(an.handlers, func(ad *AlertData) { an.handleOpsGenie(&pipeline.OpsGenieHandler{}, ad) }) } for _, talk := range n.TalkHandlers { talk := talk an.handlers = append(an.handlers, func(ad *AlertData) { an.handleTalk(talk, ad) }) } // Parse level expressions an.levels = make([]*tick.StatefulExpr, CritAlert+1) if n.Info != nil { an.levels[InfoAlert] = tick.NewStatefulExpr(n.Info) } if n.Warn != nil { an.levels[WarnAlert] = tick.NewStatefulExpr(n.Warn) } if n.Crit != nil { an.levels[CritAlert] = tick.NewStatefulExpr(n.Crit) } // Setup states if n.History < 2 { n.History = 2 } an.states = make(map[models.GroupID]*alertState) // Configure flapping if n.UseFlapping { if n.FlapLow > 1 || n.FlapHigh > 1 { return nil, errors.New("alert flap thresholds are percentages and should be between 0 and 1") } } return }