/// <summary> /// Initializes a new Producer instance. /// </summary> /// <param name="config"> /// librdkafka configuration parameters (refer to https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md) /// TODO: Link to confluent-kafka-dotnet page with dotnet specific parameters also (i.e. default.topic.config). /// </param> /// <param name="manualPoll"> /// If true, does not start a dedicated polling thread to trigger events or receive delivery reports - /// you must call the Poll method periodically instead. /// </param> /// <param name="disableDeliveryReports"> /// If true, disables notification of delivery reports. Note: if set to true and you use a ProduceAsync variant that return /// a Task, the Tasks will never complete. Generally you should leave this parameter as false. Set it to true for "fire and /// forget" semantics and a small boost in performance. /// </param> public Producer(IEnumerable <KeyValuePair <string, object> > config, bool manualPoll = false, bool disableDeliveryReports = false) { this.topicConfig = (IEnumerable <KeyValuePair <string, object> >)config.FirstOrDefault(prop => prop.Key == "default.topic.config").Value; this.manualPoll = manualPoll; this.disableDeliveryReports = disableDeliveryReports; var configHandle = SafeConfigHandle.Create(); config .Where(prop => prop.Key != "default.topic.config") .ToList() .ForEach((kvp) => { configHandle.Set(kvp.Key, kvp.Value.ToString()); }); IntPtr configPtr = configHandle.DangerousGetHandle(); if (!disableDeliveryReports) { LibRdKafka.conf_set_dr_msg_cb(configPtr, DeliveryReportCallback); } // TODO: provide some mechanism whereby calls to the error and log callbacks are cached until // such time as event handlers have had a chance to be registered. LibRdKafka.conf_set_error_cb(configPtr, ErrorCallback); LibRdKafka.conf_set_log_cb(configPtr, LogCallback); LibRdKafka.conf_set_stats_cb(configPtr, StatsCallback); this.kafkaHandle = SafeKafkaHandle.Create(RdKafkaType.Producer, configPtr); if (!manualPoll) { callbackCts = new CancellationTokenSource(); callbackTask = StartPollTask(callbackCts.Token); } }
internal void Init(RdKafkaType type, IntPtr config, Config.LogCallback logger) { ErrorDelegate = (IntPtr rk, ErrorCode err, string reason, IntPtr opaque) => { OnError?.Invoke(this, new ErrorArgs() { ErrorCode = err, Reason = reason }); }; LibRdKafka.conf_set_error_cb(config, ErrorDelegate); if (logger == null) { logger = ((string handle, int level, string fac, string buf) => { var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); Console.WriteLine($"{level}|{now}|{handle}|{fac}| {buf}"); }); } LogDelegate = (IntPtr rk, int level, string fac, string buf) => { // The log_cb is called very early during construction, before // SafeKafkaHandle or any of the C# wrappers are ready. // So we can't really pass rk on, just pass the rk name instead. var name = Marshal.PtrToStringAnsi(LibRdKafka.name(rk)); logger(name, level, fac, buf); }; LibRdKafka.conf_set_log_cb(config, LogDelegate); StatsDelegate = (IntPtr rk, IntPtr json, UIntPtr json_len, IntPtr opaque) => { OnStatistics?.Invoke(this, Marshal.PtrToStringAnsi(json)); return(0); }; LibRdKafka.conf_set_stats_cb(config, StatsDelegate); handle = SafeKafkaHandle.Create(type, config); callbackCts = new CancellationTokenSource(); callbackTask = StartCallbackTask(callbackCts.Token); }