package core.framework.impl.kafka; import core.framework.api.kafka.MessagePublisher; import core.framework.api.log.ActionLogContext; import core.framework.api.util.Maps; import core.framework.api.util.Network; import core.framework.api.util.StopWatch; import core.framework.api.util.Types; import core.framework.impl.json.JSONWriter; import core.framework.impl.log.ActionLog; import core.framework.impl.log.LogManager; import core.framework.impl.log.LogParam; import org.apache.kafka.clients.producer.Producer; import org.apache.kafka.clients.producer.ProducerRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; /** * @author neo */ public class KafkaMessagePublisher<T> implements MessagePublisher<T> { private final Logger logger = LoggerFactory.getLogger(KafkaMessagePublisher.class); private final Producer<String, byte[]> producer; private final MessageValidator validator; private final String topic; private final LogManager logManager; private final JSONWriter<KafkaMessage<T>> writer; public KafkaMessagePublisher(Producer<String, byte[]> producer, MessageValidator validator, String topic, Class<T> messageClass, LogManager logManager) { this.producer = producer; this.validator = validator; this.topic = topic; this.logManager = logManager; writer = JSONWriter.of(Types.generic(KafkaMessage.class, messageClass)); } @Override public void publish(String key, T value) { publish(topic, key, value); } @Override public void publish(String topic, String key, T value) { validator.validate(value); StopWatch watch = new StopWatch(); try { KafkaMessage<T> kafkaMessage = new KafkaMessage<>(); Map<String, String> headers = Maps.newHashMap(); headers.put(KafkaMessage.HEADER_CLIENT_IP, Network.localHostAddress()); headers.put(KafkaMessage.HEADER_CLIENT, logManager.appName); linkContext(headers); kafkaMessage.headers = headers; kafkaMessage.value = value; byte[] message = writer.toJSON(kafkaMessage); logger.debug("publish, topic={}, key={}, message={}", topic, key, LogParam.of(message)); producer.send(new ProducerRecord<>(topic, key, message)); } finally { long elapsedTime = watch.elapsedTime(); ActionLogContext.track("kafka", elapsedTime); // kafka producer send message in background, the main purpose of track is to count how many message sent in action logger.debug("publish, topic={}, key={}, elapsedTime={}", topic, key, elapsedTime); } } private void linkContext(Map<String, String> headers) { ActionLog actionLog = logManager.currentActionLog(); if (actionLog == null) return; headers.put(KafkaMessage.HEADER_REF_ID, actionLog.refId()); if (actionLog.trace) headers.put(KafkaMessage.HEADER_TRACE, "true"); } }