-
Notifications
You must be signed in to change notification settings - Fork 915
expose stats_cb #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
expose stats_cb #55
Changes from all commits
201b6b3
8f88eb1
73b363f
d7ab475
eb31ace
90d11df
495a836
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,24 +18,55 @@ | |
# | ||
# Example high-level Kafka 0.9 balanced Consumer | ||
# | ||
|
||
from confluent_kafka import Consumer, KafkaException, KafkaError | ||
import sys | ||
import getopt | ||
import json | ||
from pprint import pformat | ||
|
||
if __name__ == '__main__': | ||
if len(sys.argv) < 4: | ||
sys.stderr.write('Usage: %s <bootstrap-brokers> <group> <topic1> <topic2> ..\n' % sys.argv[0]) | ||
sys.exit(1) | ||
def stats_cb(stats_json_str): | ||
stats_json = json.loads(stats_json_str) | ||
print('\nKAFKA Stats: {}\n'.format(pformat(stats_json))) | ||
|
||
broker = sys.argv[1] | ||
group = sys.argv[2] | ||
topics = sys.argv[3:] | ||
def print_usage_and_exit(program_name): | ||
sys.stderr.write('Usage: %s [options..] <bootstrap-brokers> <group> <topic1> <topic2> ..\n' % program_name) | ||
options=''' | ||
Options: | ||
-T <intvl> Enable client statistics at specified interval (ms) | ||
''' | ||
sys.stderr.write(options) | ||
sys.exit(1) | ||
|
||
|
||
if __name__ == '__main__': | ||
optlist, argv = getopt.getopt(sys.argv[1:], 'T:') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
if len(argv) < 3: | ||
print_usage_and_exit(sys.argv[0]) | ||
|
||
broker = argv[0] | ||
group = argv[1] | ||
topics = argv[2:] | ||
# Consumer configuration | ||
# See https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md | ||
conf = {'bootstrap.servers': broker, 'group.id': group, 'session.timeout.ms': 6000, | ||
'default.topic.config': {'auto.offset.reset': 'smallest'}} | ||
|
||
# Check to see if -T option exists | ||
for opt in optlist: | ||
if opt[0] != '-T': | ||
continue | ||
try: | ||
intval = int(opt[1]) | ||
except: | ||
sys.stderr.write("Invalid option value for -T: %s\n" % opt[1]) | ||
sys.exit(1) | ||
|
||
if intval <= 0: | ||
sys.stderr.write("-T option value needs to be larger than zero: %s\n" % opt[1]) | ||
sys.exit(1) | ||
|
||
conf['stats_cb'] = stats_cb | ||
conf['statistics.interval.ms'] = int(opt[1]) | ||
|
||
# Create Consumer instance | ||
c = Consumer(**conf) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
import time | ||
import uuid | ||
import sys | ||
import json | ||
|
||
try: | ||
from progress.bar import Bar | ||
|
@@ -35,10 +36,12 @@ | |
bootstrap_servers = 'localhost' | ||
|
||
|
||
|
||
# global variable to be set by stats_cb call back function | ||
good_stats_cb_result = False | ||
|
||
def error_cb (err): | ||
print('Error: %s' % err) | ||
|
||
|
||
class MyTestDr(object): | ||
""" Producer: Delivery report callback """ | ||
|
@@ -353,6 +356,82 @@ def my_on_revoke (consumer, partitions): | |
c.close() | ||
|
||
|
||
def verify_stats_cb(): | ||
""" Verify stats_cb """ | ||
|
||
def stats_cb(stats_json_str): | ||
global good_stats_cb_result | ||
stats_json = json.loads(stats_json_str) | ||
if 'test' in stats_json['topics']: | ||
app_offset = stats_json['topics']['test']['partitions']['0']['app_offset'] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably want to wrap this in a try: if any of the sub-dict keys are missing and just print the json blob on failure. |
||
if app_offset > 0: | ||
print("# app_offset stats for topic test partition 0: %d" % app_offset) | ||
good_stats_cb_result = True | ||
|
||
conf = {'bootstrap.servers': bootstrap_servers, | ||
'group.id': uuid.uuid1(), | ||
'session.timeout.ms': 6000, | ||
'error_cb': error_cb, | ||
'stats_cb': stats_cb, | ||
'statistics.interval.ms': 200, | ||
'default.topic.config': { | ||
'auto.offset.reset': 'earliest' | ||
}} | ||
|
||
c = confluent_kafka.Consumer(**conf) | ||
c.subscribe(["test"]) | ||
|
||
max_msgcnt = 1000000 | ||
bytecnt = 0 | ||
msgcnt = 0 | ||
|
||
print('Will now consume %d messages' % max_msgcnt) | ||
|
||
if with_progress: | ||
bar = Bar('Consuming', max=max_msgcnt, | ||
suffix='%(index)d/%(max)d [%(eta_td)s]') | ||
else: | ||
bar = None | ||
|
||
while not good_stats_cb_result: | ||
# Consume until EOF or error | ||
|
||
msg = c.poll(timeout=20.0) | ||
if msg is None: | ||
raise Exception('Stalled at %d/%d message, no new messages for 20s' % | ||
(msgcnt, max_msgcnt)) | ||
|
||
if msg.error(): | ||
if msg.error().code() == confluent_kafka.KafkaError._PARTITION_EOF: | ||
# Reached EOF for a partition, ignore. | ||
continue | ||
else: | ||
raise confluent_kafka.KafkaException(msg.error()) | ||
|
||
|
||
bytecnt += len(msg) | ||
msgcnt += 1 | ||
|
||
if bar is not None and (msgcnt % 10000) == 0: | ||
bar.next(n=10000) | ||
|
||
if msgcnt == 1: | ||
t_first_msg = time.time() | ||
if msgcnt >= max_msgcnt: | ||
break | ||
|
||
if bar is not None: | ||
bar.finish() | ||
|
||
if msgcnt > 0: | ||
t_spent = time.time() - t_first_msg | ||
print('%d messages (%.2fMb) consumed in %.3fs: %d msgs/s, %.2f Mb/s' % \ | ||
(msgcnt, bytecnt / (1024*1024), t_spent, msgcnt / t_spent, | ||
(bytecnt / t_spent) / (1024*1024))) | ||
|
||
print('closing consumer') | ||
c.close() | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
|
@@ -377,6 +456,9 @@ def my_on_revoke (consumer, partitions): | |
print('=' * 30, 'Verifying Consumer performance', '=' * 30) | ||
verify_consumer_performance() | ||
|
||
print('=' * 30, 'Verifying stats_cb', '=' * 30) | ||
verify_stats_cb() | ||
|
||
print('=' * 30, 'Done', '=' * 30) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
#!/usr/bin/env python | ||
|
||
import confluent_kafka | ||
|
||
import json | ||
import time | ||
from pprint import pprint | ||
|
||
def test_version(): | ||
print('Using confluent_kafka module version %s (0x%x)' % confluent_kafka.version()) | ||
|
@@ -14,3 +16,54 @@ def test_version(): | |
assert len(sver) > 0 | ||
assert iver > 0 | ||
|
||
# global variable for error_cb call back function | ||
seen_error_cb = False | ||
|
||
def test_error_cb(): | ||
""" Tests error_cb. """ | ||
|
||
def error_cb(error_msg): | ||
global seen_error_cb | ||
seen_error_cb = True | ||
assert error_msg.code() in (confluent_kafka.KafkaError._TRANSPORT, confluent_kafka.KafkaError._ALL_BROKERS_DOWN) | ||
|
||
conf = {'bootstrap.servers': 'localhost:9093', # Purposely cause connection refused error | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is actually probably the second most likely port to find a broker on localhost, so maybe you want to connect to localhost:22 or somesuch that will definately not a Kafka broker. |
||
'group.id':'test', | ||
'socket.timeout.ms':'100', | ||
'session.timeout.ms': 1000, # Avoid close() blocking too long | ||
'error_cb': error_cb | ||
} | ||
|
||
kc = confluent_kafka.Consumer(**conf) | ||
kc.subscribe(["test"]) | ||
while not seen_error_cb: | ||
kc.poll(timeout=1) | ||
|
||
kc.close() | ||
|
||
# global variable for stats_cb call back function | ||
seen_stats_cb = False | ||
|
||
def test_stats_cb(): | ||
""" Tests stats_cb. """ | ||
|
||
def stats_cb(stats_json_str): | ||
global seen_stats_cb | ||
seen_stats_cb = True | ||
stats_json = json.loads(stats_json_str) | ||
assert len(stats_json['name']) > 0 | ||
|
||
conf = {'group.id':'test', | ||
'socket.timeout.ms':'100', | ||
'session.timeout.ms': 1000, # Avoid close() blocking too long | ||
'statistics.interval.ms': 200, | ||
'stats_cb': stats_cb | ||
} | ||
|
||
kc = confluent_kafka.Consumer(**conf) | ||
|
||
kc.subscribe(["test"]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing as suggested for error_cb |
||
while not seen_stats_cb: | ||
kc.poll(timeout=1) | ||
kc.close() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to check here and for error_cb if the object is callable (
PyCallable_Check(vo)
) (Py_None is okay too)