In this short blog, we'll use Slack API to send alert messages to a dedicated Slack channel created for the purpose.
Pre-requisites
To get started, go to https://api.slack.com/apps.
- Login to your workspace.
- Create an application in your workspace.
- Create a private channel in the workspace where you want to receive alert messages.
- Activate Incoming Webhooks. This allows us to post messages from external sources into Slack.
At this point, we have a Webhook URL to which you can post messages. The messages will then appear in the channel that you've created.
Sending Message to Slack
To send message to a Slack channel programmatically, we'll need a client to send a HTTP POST message. Let us use Jersey HTTP client for the purpose. Jersey is an open source framework for developing Web services using REST.
Let's start by including dependencies.
- Jersey client
- Jackson as JSON provider
- json to create JSON object
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>3.1.7</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>
Let's create a representation of an Alert object that we want to send to Slack.
package none.rks;
public class Alert {
private String id;
private String source;
private String name;
private String details;
public Alert(String id, String source, String name, String details) {
this.id = id;
this.source = source;
this.name = name;
this.details = details;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
}
You have to add getters and setters for Jackson to serialize Alert object.
Next, let's use Jersey client to develop a simple REST client that will send an Alert object over HTTP POST to Slack API.
package none.rks;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.glassfish.jersey.logging.LoggingFeature;
import org.json.JSONObject;
import java.util.logging.Level;
public class SlackIntegrationDemo {
private static final String REST_URI
= "<slack-url>";
private Client client = ClientBuilder.newBuilder()
.register(LoggingFeature.class)
.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY)
.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, Level.INFO.getName())
.build();
public Response sendAlert(Alert alert) throws JsonProcessingException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("text", new ObjectMapper().writeValueAsString(alert));
return client
.target(REST_URI)
.request(MediaType.APPLICATION_JSON)
.acceptEncoding("UTF-8")
.post(Entity.entity(jsonObject.toString(), MediaType.APPLICATION_JSON));
}
public static void main(String[] args) throws JsonProcessingException {
Response response = new SlackIntegrationDemo().sendAlert(new Alert("1", "SI", "Ransomware Alert", "123"));
System.out.println(response);
}
}
Notice the use of Logging feature provided by Jersey client to log all the HTTP request and response.
!! Important !! The POST message must have an attribute text for Slack API to accept your HTTP request. Otherwise it will return 400 Bad Request.
Let's build and run our sample.
Jun 01, 2024 5:13:46 AM org.glassfish.jersey.client.innate.inject.NonInjectionManager <init>
WARNING: Falling back to injection-less client.
Jun 01, 2024 5:13:47 AM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Sending client request on thread main
1 > POST https://hooks.slack.com/services/XXXX
1 > Accept: application/json
1 > Accept-Encoding: UTF-8
1 > Content-Type: application/json
{"text":"{\"id\":\"1\",\"source\":\"SI\",\"name\":\"Ransomware Alert\",\"details\":\"123\"}"}
Jun 01, 2024 5:13:47 AM org.glassfish.jersey.logging.LoggingInterceptor log
INFO: 1 * Client response received on thread main
1 < 200
1 < access-control-allow-origin: *
1 < content-length: 2
1 < content-type: text/html
1 < date: Fri, 31 May 2024 23:43:47 GMT
1 < referrer-policy: no-referrer
1 < server: Apache
1 < strict-transport-security: max-age=31536000; includeSubDomains; preload
1 < vary: Accept-Encoding
1 < via: 1.1 slack-prod.tinyspeck.com, envoy-www-iad-nvkphqdz, envoy-edge-canary-bom-hymqoqzd
1 < x-backend: main_normal main_canary_with_overflow main_control_with_overflow
1 < x-edge-backend: envoy-www
1 < x-envoy-attempt-count: 1
1 < x-envoy-upstream-service-time: 235
1 < x-frame-options: SAMEORIGIN
1 < x-server: slack-www-hhvm-main-iad-kgmh
1 < x-slack-backend: r
1 < x-slack-edge-shared-secret-outcome: no-match
1 < x-slack-shared-secret-outcome: no-match
1 < x-slack-unique-id: Zlpgs49S2iDdn326GsSrpAAAABs
ok
InboundJaxrsResponse{context=ClientResponse{method=POST, uri=https://hooks.slack.com/services/XXXX, status=200, reason=OK}}
The message is delivered to the Slack channel shown below.