please help me to register custom exporter
here is what I did till now
package org.rutusoft.email;
import io.camunda.zeebe.exporter.api.Exporter;
import io.camunda.zeebe.exporter.api.context.Context;
import io.camunda.zeebe.exporter.api.context.Controller;
import io.camunda.zeebe.protocol.record.Record;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public final class EmailNotificationExporter implements Exporter {
private static Logger logger = LogManager.getLogger(EmailNotificationExporter.class);
@Override
public void configure(Context context) throws Exception {
Exporter.super.configure(context);
}
@Override
public void open(Controller controller) {
Exporter.super.open(controller);
}
@Override
public void close() {
Exporter.super.close();
}
@Override
public void export(Record<?> record) {
}
}
pom.xml file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>email-exporter</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>email-exporter</name>
<url>http://maven.apache.org</url>
<properties>
<exporter.finalName>${project.artifactId}-${project.version}</exporter.finalName>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.camunda/zeebe-exporter-api -->
<dependency>
<groupId>io.camunda</groupId>
<artifactId>zeebe-exporter-api</artifactId>
<!-- <version>8.4.4</version>-->
<version>8.5.0-alpha1</version>
</dependency>
<dependency>
<groupId>io.camunda</groupId>
<artifactId>zeebe-client-java</artifactId>
<version>8.4.4</version>
<!-- <scope>test</scope>-->
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.25.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.23.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sun.mail/smtp -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>smtp</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.1</version>
</dependency>
</dependencies>
<build>
<finalName>${exporter.finalName}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<ignoredUnusedDeclaredDependencies>
<!-- false positive, used as logging output in tests -->
<unusedDeclaredDependency>org.slf4j:slf4j-simple</unusedDeclaredDependency>
</ignoredUnusedDeclaredDependencies>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version> <!-- Make sure to use the appropriate version -->
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>standalone</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version> <!-- Use the appropriate version -->
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
zeebe broker config
exporters:
email:
className: EmailNotificationExporter
# jarPath: exporters/email-exporter-1.0-SNAPSHOT-jar-with-dependencies.jar
jarPath: exporters/email-exporter-1.0-SNAPSHOT.jar
Hi @sinugaud - how do you have Camunda Self-Managed deployed (Docker, Helm, something else)? This guide shows how to do this with Helm:
If you are using Docker, the approach similar: you need to copy the JAR file to the exporters
folder in the Zeebe container. If you search the forums, there are several threads with people installing custom exporters that may be helpful also.
Hi @nathan.loding - I have Camunda Self-Managed setup, I followed that related document,I built a jar put in Zeebe exporter, and configured it, but it does not work, I’m getting class not found
I am assuming that some steps I missed or documents are outdated
Hi @sinugaud - please share as many details as you can:
- What is the full error?
- Are you using Helm or Docker (or something else)?
- What version of Zeebe are you running?
- Share your Helm or Docker configuration (with secrets removed)
Hi @nathan.loding , at the moment, I’m utilizing the Hazelcast Exporter and have made some adjustments to it.
Give me some time I will share all the details
Hi @nathan.loding
there is are change in configration here is all details:
What I did till now
Here is my pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Incident-exporter</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Incident-exporter</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.camunda</groupId>
<artifactId>zeebe-exporter-api</artifactId>
<version>8.4.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.16.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
<execution>
<id>assemble-for-jib</id>
<phase>compile</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/jib</outputDirectory>
<finalName>${project.artifactId}</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package io.zeebe.incident.exporter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.camunda.zeebe.exporter.api.Exporter;
import io.camunda.zeebe.exporter.api.context.Context;
import io.camunda.zeebe.exporter.api.context.Controller;
import io.camunda.zeebe.protocol.record.Record;
import io.camunda.zeebe.protocol.record.RecordType;
import org.slf4j.Logger;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
public class IncidentExporter implements Exporter {
private Logger logger;
@Override
public void configure(Context context) throws Exception {
logger = context.getLogger();
Exporter.super.configure(context);
}
@Override
public void open(Controller controller) {
Exporter.super.open(controller);
}
@Override
public void close() {
Exporter.super.close();
}
@Override
public void export(Record<?> record) {
RecordType recordType = record.getRecordType();
String intent = String.valueOf(record.getIntent());
logger.info("Record type String: {}", recordType);
logger.info("Record intent String: {}", intent);
String processInstanceKey;
Object value = record.getValue();
String jsonString = value.toString();
logger.info("Record value String: {}", jsonString);
ObjectMapper objectMapper = new ObjectMapper();
try {
JsonNode jsonNode = objectMapper.readTree(jsonString);
processInstanceKey = jsonNode.get("processInstanceKey").asText();
logger.info("Process Instance Key: " + processInstanceKey);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
// Prepare data for sending via REST
String dataToSend = prepareData(processInstanceKey, intent, String.valueOf(recordType));
logger.info("data to send : {}", dataToSend);
// Send data via REST API
sendViaRestApi(dataToSend);
}
private String prepareData(String processInstanceKey, String intent, String recordType) {
// Prepare data as needed
return "{ \"processInstanceKey\": \"" + processInstanceKey + "\", \"intent\": \"" + intent + "\", \"recordType\": \"" + recordType + "\" }";
}
// private byte[] recordToProtobuf(Record record) {
// final Schema.Record dto = RecordTransformer.toGenericRecord(record);
// return dto.toByteArray();
// }
//
// private byte[] recordToJson(Record record) {
// final var json = record.toJson();
// return json.getBytes();
// }
private String sendViaRestApi(String data) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8087/instance/record";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<>(data, headers);
logger.info(" response.getStatusCode(): {}", data);
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
logger.info(" response: {}", response.getStatusCode());
return response.getBody();
} else {
logger.info(" response: {}", response.getStatusCode());
throw new RuntimeException("Failed to send data via REST API. Status code: " + response.getStatusCode());
}
}
}
Zeebe configuration
exporters:
incident:
className: io.zeebe.incident.exporter.IncidentExporter
jarPath: /exporters/Incident-exporter-1.0-SNAPSHOT-jar-with-dependencies.jar
java.lang.IllegalStateException: Failed to load exporter with configuration: ExporterCfg{, jarPath='D:\zeebe-camunda\exporters\camunda-zeebe-8.4.4\exporters\Incident-exporter-1.0-SNAPSHOT-jar-with-dependencies.jar', className='io.zeebe.incident.exporter.IncidentExporter', args=null}
at io.camunda.zeebe.broker.Broker.buildExporterRepository(Broker.java:150) ~[zeebe-broker-8.4.4.jar:8.4.4]
Caused by: java.lang.ClassCastException: class io.zeebe.incident.exporter.IncidentExporter
Caused by: io.camunda.zeebe.broker.exporter.repo.ExporterLoadException: Cannot load exporter [incident]: cannot load specified class
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext - Exception thrown from ApplicationListener handling ContextClosedEvent
java.lang.NullPointerException: Cannot invoke "io.camunda.zeebe.broker.Broker.close()" because "this.broker" is null
- Are you using Helm or Docker (or something else)?
and -: No I am using self-managed later shift to docker-compose
- What version of Zeebe are you running?
8.4.4
- Share your Helm or Docker configuration (with secrets removed)
Hi @sinugaud - I believe the issue might be the inclusion of Spring. If you look at the existing exporters, including the Hazelcast exporter, they don’t use Spring. I believe Spring creates an executable JAR rather than one that can be imported as a class.
Hi @nathan.loding - I tried adding spring-web maven in hazelcast exporter it is working fine for me , also I tried without spring-web jar in this exporter but am still getting the same error, Are there other methods to register the exporter
Hi,
Any followups on this? My team is facing exactly the same problem.
@nathan.loding, I love to see in your avatar the same baloon that you wore in Berlin 
Thanks,
Jaime
1 Like
Hey @mosteja ,
I did a temporary fix for now I cloned the kafka exporter repo I changed there logic
and it work for now,
let me know if you get any solution regarding this