|
16 | 16 | */ |
17 | 17 | package org.graylog.integrations.pagerduty.client; |
18 | 18 |
|
| 19 | +import com.floreysoft.jmte.Engine; |
19 | 20 | import com.google.common.collect.ImmutableList; |
20 | 21 | import jakarta.inject.Inject; |
21 | | -import org.apache.commons.lang3.StringUtils; |
| 22 | +import jakarta.inject.Named; |
| 23 | +import org.apache.commons.lang3.Strings; |
22 | 24 | import org.graylog.events.notifications.EventNotificationContext; |
23 | 25 | import org.graylog.events.notifications.EventNotificationModelData; |
24 | 26 | import org.graylog.events.notifications.EventNotificationService; |
25 | | -import org.graylog.events.processor.EventDefinitionDto; |
26 | | -import org.graylog.events.processor.aggregation.AggregationEventProcessorConfig; |
| 27 | +import org.graylog.events.notifications.TemplateModelProvider; |
27 | 28 | import org.graylog.integrations.pagerduty.PagerDutyNotificationConfig; |
28 | 29 | import org.graylog.integrations.pagerduty.dto.Link; |
29 | 30 | import org.graylog.integrations.pagerduty.dto.PagerDutyMessage; |
30 | 31 | import org.graylog2.plugin.MessageSummary; |
31 | | -import org.graylog2.plugin.streams.Stream; |
32 | | -import org.graylog2.streams.StreamService; |
33 | 32 | import org.graylog2.web.customization.CustomizationConfig; |
| 33 | +import org.joda.time.DateTimeZone; |
34 | 34 |
|
35 | 35 | import java.net.MalformedURLException; |
36 | 36 | import java.net.URI; |
|
40 | 40 | import java.util.List; |
41 | 41 | import java.util.Locale; |
42 | 42 | import java.util.Map; |
43 | | -import java.util.stream.Collectors; |
44 | 43 |
|
45 | 44 | /** |
46 | 45 | * Factory class for PagerDuty messages, heavily based on the works of the cited authors. |
|
52 | 51 | * @author Edgar Molina |
53 | 52 | */ |
54 | 53 | public class MessageFactory { |
55 | | - private static final List<String> PAGER_DUTY_PRIORITIES = Arrays.asList("info", "warning", "critical"); |
| 54 | + private static final List<String> PAGER_DUTY_PRIORITIES = Arrays.asList("info", "warning", "critical", "critical"); |
56 | 55 |
|
57 | | - private final StreamService streamService; |
58 | 56 | private final EventNotificationService eventNotificationService; |
59 | 57 | private final CustomizationConfig customizationConfig; |
| 58 | + private final Engine templateEngine; |
| 59 | + private final TemplateModelProvider templateModelProvider; |
60 | 60 |
|
61 | 61 | @Inject |
62 | | - MessageFactory(StreamService streamService, EventNotificationService eventNotificationService, |
63 | | - CustomizationConfig customizationConfig) { |
64 | | - this.streamService = streamService; |
| 62 | + MessageFactory(EventNotificationService eventNotificationService, |
| 63 | + CustomizationConfig customizationConfig, |
| 64 | + @Named("JsonSafe") Engine jsonTemplateEngine, |
| 65 | + TemplateModelProvider templateModelProvider) { |
65 | 66 | this.eventNotificationService = eventNotificationService; |
66 | 67 | this.customizationConfig = customizationConfig; |
| 68 | + this.templateEngine = jsonTemplateEngine; |
| 69 | + this.templateModelProvider = templateModelProvider; |
67 | 70 | } |
68 | 71 |
|
69 | 72 | public PagerDutyMessage createTriggerMessage(EventNotificationContext ctx) { |
70 | 73 | final ImmutableList<MessageSummary> backlog = eventNotificationService.getBacklogForEvent(ctx); |
71 | 74 | final EventNotificationModelData modelData = EventNotificationModelData.of(ctx, backlog); |
72 | 75 | final PagerDutyNotificationConfig config = (PagerDutyNotificationConfig) ctx.notificationConfig(); |
| 76 | + final Map<String, Object> messageModel = getCustomMessageModel(ctx, backlog); |
73 | 77 |
|
74 | | - String eventTitle = modelData.eventDefinitionTitle(); |
| 78 | + final String eventTitle = config.pagerDutyTitle() |
| 79 | + .map(customTitle -> templateEngine.transform(customTitle, messageModel)) |
| 80 | + .orElse(modelData.eventDefinitionTitle()); |
75 | 81 | String eventPriority = PAGER_DUTY_PRIORITIES.get(0); |
76 | 82 | int priority = ctx.eventDefinition().get().priority() - 1; |
77 | | - if (priority >= 0 && priority <= 2) { |
| 83 | + if (priority >= 0 && priority <= 3) { |
78 | 84 | eventPriority = PAGER_DUTY_PRIORITIES.get(priority); |
79 | 85 | } |
80 | 86 |
|
81 | | - List<Link> streamLinks = |
82 | | - streamService |
83 | | - .loadByIds(modelData.event().sourceStreams()) |
84 | | - .stream() |
85 | | - .map(stream -> buildStreamWithUrl(stream, ctx, config)) |
86 | | - .collect(Collectors.toList()); |
| 87 | + final List<Link> replayLink; |
| 88 | + try { |
| 89 | + final String replayUrl = Strings.CS.appendIfMissing( |
| 90 | + config.clientUrl(), "/") + "alerts/" + modelData.event().id() + "/replay-search"; |
| 91 | + replayLink = List.of(new Link(new URI(replayUrl).toURL(), "Replay Event")); |
| 92 | + } catch (URISyntaxException | MalformedURLException e) { |
| 93 | + throw new IllegalStateException("Error when building the event replay URL.", e); |
| 94 | + } |
87 | 95 |
|
88 | 96 | String dedupKey = ""; |
89 | 97 | if (config.customIncident()) { |
90 | | - dedupKey = String.format(Locale.ROOT, |
91 | | - "%s/%s/%s", config.keyPrefix(), modelData.event().sourceStreams(), eventTitle); |
| 98 | + final String formattedPrefix = templateEngine.transform(config.keyPrefix(), messageModel); |
| 99 | + final String prefixedIncidentKey = String.format(Locale.ROOT, |
| 100 | + "%s/%s/%s", formattedPrefix, modelData.event().sourceStreams(), eventTitle); |
| 101 | + // Use the custom incident key if provided, otherwise fall back to the prefixed key. |
| 102 | + dedupKey = config.incidentKey() |
| 103 | + .map(incidentKeyTemplate -> templateEngine.transform(incidentKeyTemplate, messageModel)) |
| 104 | + .orElse(prefixedIncidentKey); |
92 | 105 | } |
93 | 106 |
|
94 | | - |
95 | | - Map<String, String> payload = new HashMap<String, String>(); |
96 | | - payload.put("summary", modelData.event().message()); |
| 107 | + Map<String, Object> payload = new HashMap<>(); |
| 108 | + payload.put("summary", config.pagerDutyTitle() |
| 109 | + .map(customTitle -> templateEngine.transform(customTitle, messageModel)) |
| 110 | + .orElse(modelData.event().message())); |
97 | 111 | payload.put("source", customizationConfig.productName() + ":" + modelData.event().sourceStreams()); |
98 | 112 | payload.put("severity", eventPriority); |
99 | 113 | payload.put("timestamp", modelData.event().eventTimestamp().toString()); |
100 | 114 | payload.put("component", "GraylogAlerts"); |
101 | 115 | payload.put("group", modelData.event().sourceStreams().toString()); |
102 | 116 | payload.put("class", "alerts"); |
| 117 | + payload.put("custom_details", ctx.event().fields()); |
103 | 118 |
|
104 | 119 | return new PagerDutyMessage( |
105 | 120 | config.routingKey(), |
106 | 121 | "trigger", |
107 | 122 | dedupKey, |
108 | 123 | config.clientName(), |
109 | 124 | config.clientUrl(), |
110 | | - streamLinks, |
| 125 | + replayLink, |
111 | 126 | payload); |
112 | 127 | } |
113 | 128 |
|
114 | | - private Link buildStreamWithUrl(Stream stream, EventNotificationContext ctx, PagerDutyNotificationConfig config) { |
115 | | - final String graylogUrl = config.clientUrl(); |
116 | | - String streamUrl = |
117 | | - StringUtils.appendIfMissing(graylogUrl, "/") + "streams/" + stream.getId() + "/search"; |
118 | | - |
119 | | - if (ctx.eventDefinition().isPresent()) { |
120 | | - EventDefinitionDto eventDefinitionDto = ctx.eventDefinition().get(); |
121 | | - if (eventDefinitionDto.config() instanceof AggregationEventProcessorConfig) { |
122 | | - String query = |
123 | | - ((AggregationEventProcessorConfig) eventDefinitionDto.config()).query(); |
124 | | - streamUrl += "?q=" + query; |
125 | | - } |
126 | | - } |
127 | | - try { |
128 | | - return new Link(new URI(streamUrl).toURL(), stream.getTitle()); |
129 | | - } catch (URISyntaxException | MalformedURLException e) { |
130 | | - throw new IllegalStateException("Error when building the stream link URL.", e); |
131 | | - } |
| 129 | + private Map<String, Object> getCustomMessageModel(EventNotificationContext ctx, List<MessageSummary> backlog) { |
| 130 | + return templateModelProvider.of(ctx, backlog, DateTimeZone.UTC, Map.of("type", PagerDutyNotificationConfig.TYPE_NAME)); |
132 | 131 | } |
133 | 132 | } |
0 commit comments