/** * Abstract method Implementation - See MsgBusInterface.hpp for details * * TODO: Consolidate this to single produce method */ void msgBus_kafka::send_bmp_raw(u_char *r_hash, obj_bgp_peer &peer, u_char *data, size_t data_len) { string r_hash_str; string p_hash_str; RdKafka::Topic *topic = NULL; hash_toStr(peer.hash_id, p_hash_str); hash_toStr(r_hash, r_hash_str); if (data_len == 0) return; while (isConnected == false) { LOG_WARN("rtr=%s: Not connected to Kafka, attempting to reconnect", router_ip.c_str()); connect(); sleep(2); } char headers[256]; size_t hdr_len = snprintf(headers, sizeof(headers), "V: %s\nC_HASH_ID: %s\nR_HASH: %s\nR_IP: %s\nL: %lu\n\n", MSGBUS_API_VERSION, collector_hash.c_str(), r_hash_str.c_str(), router_ip.c_str(), data_len); memcpy(producer_buf, headers, hdr_len); memcpy(producer_buf+hdr_len, data, data_len); topic = topicSel->getTopic(MSGBUS_TOPIC_VAR_BMP_RAW, &router_group_name, &peer_list[p_hash_str], peer.peer_as); if (topic != NULL) { SELF_DEBUG("rtr=%s: Producing bmp raw message: topic=%s key=%s, msg size = %lu", router_ip.c_str(), topic->name().c_str(), r_hash_str.c_str(), data_len); RdKafka::ErrorCode resp = producer->produce(topic, RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY /* Copy payload */, producer_buf, data_len + hdr_len, (const std::string *)&r_hash_str, NULL); if (resp != RdKafka::ERR_NO_ERROR) LOG_ERR("rtr=%s: Failed to produce bmp raw message: %s", router_ip.c_str(), RdKafka::err2str(resp).c_str()); } else { SELF_DEBUG("rtr=%s: failed to produce bmp raw message because topic couldn't be found: topic=%s key=%s, msg size = %lu", router_ip.c_str(), MSGBUS_TOPIC_VAR_BMP_RAW, r_hash_str.c_str(), data_len); } producer->poll(0); }
/** * produce message to Kafka * * \param [in] topic_var Topic var to use in KafkaTopicSelector::getTopic() MSGBUS_TOPIC_VAR_* * \param [in] msg message to produce * \param [in] msg_size Length in bytes of the message * \param [in] rows Number of rows * \param [in] key Hash key * \param [in] peer_group Peer group name - empty/NULL if not set or used * \param [in] peer_asn Peer ASN */ void msgBus_kafka::produce(const char *topic_var, char *msg, size_t msg_size, int rows, string key, const string *peer_group, uint32_t peer_asn) { size_t len; RdKafka::Topic *topic = NULL; while (isConnected == false or topicSel == NULL) { // Do not attempt to reconnect if this is the main process (router ip is null) // Changed on 10/29/15 to support docker startup delay with kafka /* if (router_ip.size() <= 0) { return; }*/ LOG_WARN("rtr=%s: Not connected to Kafka, attempting to reconnect", router_ip.c_str()); connect(); sleep(1); } char headers[256]; len = snprintf(headers, sizeof(headers), "V: %s\nC_HASH_ID: %s\nL: %lu\nR: %d\n\n", MSGBUS_API_VERSION, collector_hash.c_str(), msg_size, rows); memcpy(producer_buf, headers, len); memcpy(producer_buf+len, msg, msg_size); topic = topicSel->getTopic(topic_var, &router_group_name, peer_group, peer_asn); if (topic != NULL) { SELF_DEBUG("rtr=%s: Producing message: topic=%s key=%s, msg size = %lu", router_ip.c_str(), topic->name().c_str(), key.c_str(), msg_size); RdKafka::ErrorCode resp = producer->produce(topic, RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY, producer_buf, msg_size + len, (const std::string *) &key, NULL); if (resp != RdKafka::ERR_NO_ERROR) LOG_ERR("rtr=%s: Failed to produce message: %s", router_ip.c_str(), RdKafka::err2str(resp).c_str()); } else { LOG_NOTICE("rtr=%s: failed to produce message because topic couldn't be found: topic=%s key=%s, msg size = %lu", router_ip.c_str(), topic_var, key.c_str(), msg_size); } producer->poll(0); }
int main (int argc, char **argv) { std::string brokers = "localhost"; std::string errstr; std::vector<std::string> topics; std::string conf_file; std::string mode = "P"; int throughput = 0; int32_t partition = RdKafka::Topic::PARTITION_UA; bool do_conf_dump = false; MyHashPartitionerCb hash_partitioner; /* * Create configuration objects */ RdKafka::Conf *conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); RdKafka::Conf *tconf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC); { char hostname[128]; gethostname(hostname, sizeof(hostname)-1); conf->set("client.id", std::string("rdkafka@") + hostname, errstr); } conf->set("debug", "cgrp,topic", errstr); for (int i = 1 ; i < argc ; i++) { const char *name = argv[i]; const char *val = i+1 < argc ? argv[i+1] : NULL; if (val && !strncmp(val, "--", 2)) val = NULL; std::cout << now() << ": argument: " << name << " " << (val?val:"") << std::endl; if (val) { if (!strcmp(name, "--topic")) topics.push_back(val); else if (!strcmp(name, "--broker-list")) brokers = val; else if (!strcmp(name, "--max-messages")) state.maxMessages = atoi(val); else if (!strcmp(name, "--throughput")) throughput = atoi(val); else if (!strcmp(name, "--producer.config") || !strcmp(name, "--consumer.config")) read_conf_file(val); else if (!strcmp(name, "--group-id")) conf->set("group.id", val, errstr); else if (!strcmp(name, "--session-timeout")) conf->set("session.timeout.ms", val, errstr); else if (!strcmp(name, "--reset-policy")) { if (tconf->set("auto.offset.reset", val, errstr)) { std::cerr << now() << ": " << errstr << std::endl; exit(1); } } else if (!strcmp(name, "--debug")) { conf->set("debug", val, errstr); } else { std::cerr << now() << ": Unknown option " << name << std::endl; exit(1); } i++; } else { if (!strcmp(name, "--consumer")) mode = "C"; else if (!strcmp(name, "--producer")) mode = "P"; else if (!strcmp(name, "--enable-autocommit")) { state.consumer.useAutoCommit = true; conf->set("enable.auto.commit", "true", errstr); } else { std::cerr << now() << ": Unknown option or missing argument to " << name << std::endl; exit(1); } } } if (topics.empty() || brokers.empty()) { std::cerr << now() << ": Missing --topic and --broker-list" << std::endl; exit(1); } /* * Set configuration properties */ conf->set("metadata.broker.list", brokers, errstr); ExampleEventCb ex_event_cb; conf->set("event_cb", &ex_event_cb, errstr); if (do_conf_dump) { int pass; for (pass = 0 ; pass < 2 ; pass++) { std::list<std::string> *dump; if (pass == 0) { dump = conf->dump(); std::cerr << now() << ": # Global config" << std::endl; } else { dump = tconf->dump(); std::cerr << now() << ": # Topic config" << std::endl; } for (std::list<std::string>::iterator it = dump->begin(); it != dump->end(); ) { std::cerr << *it << " = "; it++; std::cerr << *it << std::endl; it++; } std::cerr << std::endl; } exit(0); } signal(SIGINT, sigterm); signal(SIGTERM, sigterm); signal(SIGALRM, sigwatchdog); if (mode == "P") { /* * Producer mode */ ExampleDeliveryReportCb ex_dr_cb; /* Set delivery report callback */ conf->set("dr_cb", &ex_dr_cb, errstr); /* * Create producer using accumulated global configuration. */ RdKafka::Producer *producer = RdKafka::Producer::create(conf, errstr); if (!producer) { std::cerr << now() << ": Failed to create producer: " << errstr << std::endl; exit(1); } std::cerr << now() << ": % Created producer " << producer->name() << std::endl; /* * Create topic handle. */ RdKafka::Topic *topic = RdKafka::Topic::create(producer, topics[0], tconf, errstr); if (!topic) { std::cerr << now() << ": Failed to create topic: " << errstr << std::endl; exit(1); } static const int delay_us = throughput ? 1000000/throughput : 0; if (state.maxMessages == -1) state.maxMessages = 1000000; /* Avoid infinite produce */ for (int i = 0 ; run && i < state.maxMessages ; i++) { /* * Produce message */ std::ostringstream msg; msg << i; RdKafka::ErrorCode resp = producer->produce(topic, partition, RdKafka::Producer::RK_MSG_COPY /* Copy payload */, const_cast<char *>(msg.str().c_str()), msg.str().size(), NULL, NULL); if (resp != RdKafka::ERR_NO_ERROR) { errorString("producer_send_error", RdKafka::err2str(resp), topic->name(), NULL, msg.str()); state.producer.numErr++; } else { std::cerr << now() << ": % Produced message (" << msg.str().size() << " bytes)" << std::endl; state.producer.numSent++; } producer->poll(delay_us / 1000); watchdog_kick(); } run = true; while (run && producer->outq_len() > 0) { std::cerr << now() << ": Waiting for " << producer->outq_len() << std::endl; producer->poll(50); watchdog_kick(); } std::cerr << now() << ": " << state.producer.numAcked << "/" << state.producer.numSent << "/" << state.maxMessages << " msgs acked/sent/max, " << state.producer.numErr << " errored" << std::endl; delete topic; delete producer; } else if (mode == "C") { /* * Consumer mode */ tconf->set("auto.offset.reset", "smallest", errstr); /* Set default topic config */ conf->set("default_topic_conf", tconf, errstr); ExampleRebalanceCb ex_rebalance_cb; conf->set("rebalance_cb", &ex_rebalance_cb, errstr); ExampleOffsetCommitCb ex_offset_commit_cb; conf->set("offset_commit_cb", &ex_offset_commit_cb, errstr); /* * Create consumer using accumulated global configuration. */ consumer = RdKafka::KafkaConsumer::create(conf, errstr); if (!consumer) { std::cerr << now() << ": Failed to create consumer: " << errstr << std::endl; exit(1); } std::cerr << now() << ": % Created consumer " << consumer->name() << std::endl; /* * Subscribe to topic(s) */ RdKafka::ErrorCode resp = consumer->subscribe(topics); if (resp != RdKafka::ERR_NO_ERROR) { std::cerr << now() << ": Failed to subscribe to " << topics.size() << " topics: " << RdKafka::err2str(resp) << std::endl; exit(1); } /* * Consume messages */ while (run) { RdKafka::Message *msg = consumer->consume(500); msg_consume(consumer, msg, NULL); delete msg; watchdog_kick(); } /* Final commit */ do_commit(consumer, 1); /* * Stop consumer */ consumer->close(); delete consumer; } /* * Wait for RdKafka to decommission. * This is not strictly needed (when check outq_len() above), but * allows RdKafka to clean up all its resources before the application * exits so that memory profilers such as valgrind wont complain about * memory leaks. */ RdKafka::wait_destroyed(5000); std::cerr << now() << ": EXITING WITH RETURN VALUE 0" << std::endl; return 0; }