11package com .strayge ;
22
3+ import static java .util .Objects .requireNonNull ;
4+
5+ import java .io .ByteArrayInputStream ;
6+ import java .io .IOException ;
7+ import java .io .InputStream ;
8+ import java .io .OutputStream ;
9+ import java .net .HttpURLConnection ;
10+ import java .net .URL ;
11+ import java .nio .charset .StandardCharsets ;
12+ import java .util .HashMap ;
13+ import java .util .Map ;
14+ import java .util .Properties ;
15+
16+ import javax .inject .Inject ;
17+
18+ import com .fasterxml .jackson .core .JsonProcessingException ;
19+ import com .fasterxml .jackson .databind .ObjectMapper ;
20+ import com .floreysoft .jmte .Engine ;
21+ import com .google .common .collect .ImmutableList ;
22+
323import org .graylog .events .notifications .EventNotification ;
424import org .graylog .events .notifications .EventNotificationContext ;
5- // import org.graylog.events.notifications.EventNotificationModelData;
6- // import org.graylog.events.notifications.EventNotificationService;
25+ import org .graylog .events .notifications .EventNotificationModelData ;
26+ import org .graylog .events .notifications .EventNotificationService ;
727import org .graylog .events .notifications .PermanentEventNotificationException ;
828import org .graylog .events .notifications .TemporaryEventNotificationException ;
9- // import org.graylog2.plugin.MessageSummary;
29+ import org .graylog2 .jackson .TypeReferences ;
30+ import org .graylog2 .notifications .NotificationService ;
31+ import org .graylog2 .plugin .MessageSummary ;
32+ import org .graylog2 .plugin .system .NodeId ;
33+ import org .graylog2 .streams .StreamService ;
34+ import org .joda .time .DateTime ;
1035import org .slf4j .Logger ;
1136import org .slf4j .LoggerFactory ;
12- // import com.google.common.collect.ImmutableList;
1337
1438/**
1539 * This is the plugin. Your class should implement one of the existing plugin
@@ -22,52 +46,149 @@ public interface Factory extends EventNotification.Factory {
2246 }
2347
2448 private static final Logger LOG = LoggerFactory .getLogger (AlertManagerNotify .class );
25- // private final EventNotificationService notificationCallbackService;
49+ private final EventNotificationService notificationCallbackService ;
50+ private final NodeId nodeId ;
51+ private final ObjectMapper objectMapper ;
52+
53+ @ Inject
54+ public AlertManagerNotify (
55+ EventNotificationService notificationCallbackService ,
56+ StreamService streamService ,
57+ NotificationService notificationService ,
58+ NodeId nodeId ,
59+ ObjectMapper objectMapper
60+ ) {
61+ this .notificationCallbackService = notificationCallbackService ;
62+ this .nodeId = requireNonNull (nodeId , "nodeId" );
63+ this .objectMapper = requireNonNull (objectMapper , "objectMapper" );
64+ }
2665
2766 @ Override
2867 public void execute (EventNotificationContext ctx ) throws TemporaryEventNotificationException , PermanentEventNotificationException {
29- LOG .info ("AlertManagerNotify.execute called" );
30-
31- final AlertManagerNotifyConfig config = (AlertManagerNotifyConfig ) ctx .notificationConfig ();
32- // config.url()
33-
34- // ImmutableList<MessageSummary> backlog = notificationCallbackService.getBacklogForEvent(ctx);
35- // final EventNotificationModelData model = EventNotificationModelData.of(ctx, backlog);
36-
37- // final EventNotificationModelData model = getModel(ctx, backlog);
38- // model.eventDefinitionTitle()
39- // ctx.notificationId()
40-
41- // final Request request = new Request.Builder()
42- // .url(httpUrl)
43- // .post(RequestBody.create(CONTENT_TYPE, body))
44- // .build();
45-
46- // try (final Response r = httpClient.newCall(request).execute()) {
47- // if (!r.isSuccessful()) {
48- // throw new PermanentEventNotificationException(
49- // "Expected successful HTTP response [2xx] but got [" + r.code() + "]. " + config.url());
50- // }
51- // } catch (IOException e) {
52- // throw new PermanentEventNotificationException(e.getMessage());
53- // }
68+ AlertManagerNotifyConfig config = (AlertManagerNotifyConfig ) ctx .notificationConfig ();
69+ ImmutableList <MessageSummary > backlog = notificationCallbackService .getBacklogForEvent (ctx );
70+ EventNotificationModelData model = EventNotificationModelData .of (ctx , backlog );
71+
72+ Engine templateEngine = Engine .createEngine ();
73+ Map <String , Object > templateModel = createTemplateModel (config , backlog , model );
74+
75+ Map <String , String > annotations = extractKeyValuePairsFromField (config .annotations ());
76+ Map <String , Object > resolvedAnnotations = transformTemplateValues (templateEngine , templateModel , annotations );
77+
78+ Map <String , String > labels = extractKeyValuePairsFromField (config .labels ());
79+ labels .put ("alertname" , config .alertName ());
80+ Map <String , Object > resolvedLabels = transformTemplateValues (templateEngine , templateModel , labels );
81+
82+ int grace_period = 1 ;
83+ if (!"" .equals (config .grace ())) {
84+ try {
85+ grace_period = Integer .parseInt (config .grace ());
86+ } catch (NumberFormatException e ) {
87+ LOG .error ("AlertManagerNotify: invalid grace period" );
88+ }
89+ }
90+ DateTime startAt = new DateTime ();
91+ DateTime endsAt = startAt .plusMinutes (grace_period ).plusSeconds (20 );
92+
93+ AlertManagerPayload payloadObject = new AlertManagerPayload ();
94+ payloadObject .annotations = resolvedAnnotations ;
95+ payloadObject .labels = resolvedLabels ;
96+ payloadObject .generatorURL = model .eventDefinitionId ();
97+ payloadObject .startsAt = startAt .toString ();
98+ payloadObject .endsAt = endsAt .toString ();
99+
100+ try {
101+ String payload = this .objectMapper .writeValueAsString (payloadObject );
102+ sendToAlertManager (config .apiUrl (), payload );
103+ } catch (JsonProcessingException e ) {
104+ throw new PermanentEventNotificationException (e .getMessage ());
105+ }
54106 }
55107
56- // private EventNotificationModelData getModel(EventNotificationContext ctx, ImmutableList<MessageSummary> backlog) {
57- // final Optional<EventDefinitionDto> definitionDto = ctx.eventDefinition();
58- // final Optional<JobTriggerDto> jobTriggerDto = ctx.jobTrigger();
59- // return EventNotificationModelData.builder()
60- // // .eventDefinition(definitionDto)
61- // .eventDefinitionId(definitionDto.map(EventDefinitionDto::id).orElse(UNKNOWN))
62- // .eventDefinitionType(definitionDto.map(d -> d.config().type()).orElse(UNKNOWN))
63- // .eventDefinitionTitle(definitionDto.map(EventDefinitionDto::title).orElse(UNKNOWN))
64- // .eventDefinitionDescription(definitionDto.map(EventDefinitionDto::description).orElse(UNKNOWN))
65- // .jobDefinitionId(jobTriggerDto.map(JobTriggerDto::jobDefinitionId).orElse(UNKNOWN))
66- // .jobTriggerId(jobTriggerDto.map(JobTriggerDto::id).orElse(UNKNOWN))
67- // .event(ctx.event())
68- // .backlog(backlog)
69- // // .backlogSize(backlog.size())
70- // .build();
71- // }
108+ private Map <String , Object > createTemplateModel (
109+ AlertManagerNotifyConfig config ,
110+ ImmutableList <MessageSummary > backlog ,
111+ EventNotificationModelData model
112+ ) {
113+
114+ Map <String , Object > templateModel = new HashMap <>();
115+ templateModel .put ("node_id" , this .nodeId );
116+ templateModel .put ("config" , objectToJson (config ));
117+ templateModel .put ("backlog" , backlog );
118+ templateModel .put ("backlog_size" , backlog .size ());
119+ templateModel .put ("context" , objectToJson (model ));
120+ templateModel .put ("event" , objectToJson (model .event ()));
121+
122+ String message = model .event ().message ();
123+ String messagePrefix = model .eventDefinitionTitle () + ": " ;
124+ if (message .startsWith (messagePrefix )) {
125+ message = message .substring (messagePrefix .length ());
126+ }
127+ templateModel .put ("message" , message );
128+ return templateModel ;
129+ }
130+
131+ private Map <String , Object > transformTemplateValues (
132+ Engine templateEngine ,
133+ Map <String , Object > templateModel ,
134+ Map <String , String > customValueMap
135+ ) {
136+ final Map <String , Object > transformedCustomValueMap = new HashMap <>();
137+ customValueMap .forEach ((key , value ) -> {
138+ if (value instanceof String ) {
139+ transformedCustomValueMap .put (key , templateEngine .transform ((String ) value , templateModel ));
140+ } else {
141+ transformedCustomValueMap .put (key , value );
142+ }
143+ });
144+ return transformedCustomValueMap ;
145+ }
146+
147+ private Map <String , String > extractKeyValuePairsFromField (String textFieldValue ) {
148+ Map <String , String > extractedPairs = new HashMap <>();
149+
150+ if (textFieldValue != null && !"" .equals (textFieldValue )) {
151+ final String preparedTextFieldValue = textFieldValue .replaceAll (";" , "\n " );
152+ Properties properties = new Properties ();
153+ InputStream stringInputStream = new ByteArrayInputStream (preparedTextFieldValue .getBytes (StandardCharsets .UTF_8 ));
154+ try {
155+ properties .load (stringInputStream );
156+ properties .forEach ((key , value ) -> extractedPairs .put ((String ) key , (String ) value ));
157+ } catch (IOException e ) {
158+ LOG .error ("AlertManagerNotify: parse property failed " + e .getMessage ());
159+ }
160+ }
161+ return extractedPairs ;
162+ }
163+
164+ private boolean sendToAlertManager (String url , String payload ) {
165+ try {
166+ payload = "[" + payload + "]" ;
167+ URL alertManagerUrl = new URL (url );
168+ HttpURLConnection connection = (HttpURLConnection ) alertManagerUrl .openConnection ();
169+ connection .setDoInput (true );
170+ connection .setDoOutput (true );
171+
172+ connection .setRequestProperty ("Content-Type" , "application/json;" );
173+ connection .setRequestProperty ("Accept" , "application/json,text/plain" );
174+ connection .setRequestProperty ("Method" , "POST" );
175+ try (OutputStream os = connection .getOutputStream ()) {
176+ os .write (payload .getBytes (StandardCharsets .UTF_8 ));
177+ }
178+ int HttpResult = connection .getResponseCode ();
179+ connection .disconnect ();
180+ if (HttpResult != HttpURLConnection .HTTP_OK ) {
181+ LOG .error ("AlertManagerNotify: AlertManager returned bad code: " + HttpResult );
182+ }
183+ return HttpResult == HttpURLConnection .HTTP_OK ;
184+ } catch (IOException e ) {
185+ LOG .error ("AlertManagerNotify: request failed " + e .getMessage ());
186+ return false ;
187+ }
188+ }
189+
190+ private Object objectToJson (Object object ) {
191+ return this .objectMapper .convertValue (object , TypeReferences .MAP_STRING_OBJECT );
192+ }
72193
73194}
0 commit comments