DUNE-DAQ
DUNE Trigger and Data Acquisition software
Toggle main menu visibility
Loading...
Searching...
No Matches
dunedaq
sourcecode
kafkaopmon
python
kafkaopmon
OpMonSubscriber.py
Go to the documentation of this file.
1
#!/usr/bin/env python3
2
3
import
getpass
4
import
logging
5
import
os
6
import
re
7
import
socket
8
import
threading
9
from
collections.abc
import
Callable
10
11
import
google.protobuf.message
as
msg
12
import
opmonlib.opmon_entry_pb2
as
entry
13
from
kafka
import
KafkaConsumer
14
15
16
class
OpMonFunction
:
17
"""Define callback function properties to store and validate function execution."""
18
19
def
__init__
(
20
self, function: Callable, opmon_id: re.Pattern, measurement: re.Pattern
21
) ->
None
:
22
"""Construct the OpMonFunction."""
23
self.
function
= function
24
self.
opmon_id
= opmon_id
25
self.
measurement
= measurement
26
return
27
28
def
match
(self, key: str) -> bool:
29
"""Validate the key follows the standard structure."""
30
opmon_id, measure = key.split(
"/"
, 1)
31
if
not
self.
opmon_id
.
match
(opmon_id):
32
return
False
33
if
not
self.
measurement
.
match
(measure):
34
return
False
35
return
True
36
37
def
execute
(self, e: entry.OpMonEntry) ->
None
:
38
"""Execute the function."""
39
self.
function
(e)
40
return
41
42
43
class
OpMonSubscriber
:
44
"""Subscribe to a kafka topic to read the contained OpMon metrics."""
45
46
def
__init__
(
47
self,
48
bootstrap: str,
49
group_id: str |
None
=
None
,
50
timeout_ms: int = 500,
51
topics: dict[str, str] |
None
=
None
,
52
) ->
None
:
53
"""Construct the OpMonSubscriber."""
54
55
self.
bootstrap
= bootstrap
56
self.
group_id
= group_id
57
self.
timeout
= timeout_ms
58
if
len(topics) == 0:
59
msg =
"Topic list is empty"
60
raise
ValueError(msg)
61
self.
topics
= topics
62
63
self.
running
=
False
64
self.
functions
= {}
65
self.
thread
= threading.Thread(target=self.
message_loop
)
66
return
67
68
def
default_id
(self) -> str:
69
"""Construct the default kafka consumer ID."""
70
node = socket.gethostname()
71
user = getpass.getuser()
72
process = os.getpid()
73
thread = threading.get_ident()
74
return
f
"{node}-{user}-{process}-{thread}"
75
76
def
add_callback
(
77
self,
78
name: str,
79
function: Callable,
80
opmon_id: str =
".*"
,
81
measurement: str =
".*"
,
82
) -> bool:
83
"""Register a callback function to the OpMonSubscriber."""
84
if
name
in
self.
functions
:
85
return
False
86
87
was_running = self.
running
88
if
was_running:
89
self.
stop
()
90
91
f =
OpMonFunction
(
92
function=function,
93
opmon_id=re.compile(opmon_id),
94
measurement=re.compile(measurement),
95
)
96
97
self.
functions
[name] = f
98
99
if
was_running:
100
self.
start
()
101
return
True
102
103
def
clear_callbacks
(self) -> None:
104
"""Remove all callback functions from the OpMonSubscriber."""
105
if
self.
running
:
106
self.
stop
()
107
self.
functions
.clear()
108
return
109
110
def
remove_callback
(self, name: str) -> bool:
111
"""Remove the named callback functions from the OpMonSubscriber."""
112
if
name
not
in
self.
functions
.keys():
113
return
False
114
115
was_running = self.
running
116
if
was_running:
117
self.
stop
()
118
119
self.
functions
.pop(name)
120
121
if
was_running
and
len(self.
functions
) > 0:
122
self.
start
()
123
return
True
124
125
def
start
(self) -> None:
126
"""Start listening to the kafka topic."""
127
logging.info(
"Starting run"
)
128
self.
running
=
True
129
self.
thread
.
start
()
130
return
131
132
def
stop
(self) -> None:
133
"""Stop listening to the kafka topic."""
134
self.
running
=
False
135
self.
thread
.join()
136
return
137
138
def
message_loop
(self) -> None:
139
"""Process entries read in with the KafkaConsumer."""
140
if
not
self.
group_id
:
141
group_id = self.
default_id
()
142
else
:
143
group_id = self.
group_id
144
145
consumer = KafkaConsumer(
146
bootstrap_servers=self.
bootstrap
,
147
group_id=group_id,
148
client_id=self.
default_id
(),
149
consumer_timeout_ms=self.
timeout
,
150
)
151
152
topics = self.
topics
153
consumer.subscribe([
"monitoring."
+ s
for
s
in
topics])
154
155
keys_str =
", "
.join(self.
functions
.keys())
156
logging.info(
"ID: %s running with functions %s"
, group_id, keys_str)
157
158
while
self.
running
:
159
try
:
160
message_it = iter(consumer)
161
message = next(message_it)
162
key = message.key.decode(
"ascii"
)
163
165
166
for
function
in
self.
functions
.values():
167
if
function.match(key):
168
e = entry.OpMonEntry()
169
e.ParseFromString(message.value)
170
function.execute(e)
171
172
except
msg.DecodeError:
173
logging.exception(
"Could not parse message"
)
174
except
StopIteration:
175
pass
176
except
Exception:
177
logging.exception(
"Unhandled exception thrown"
)
178
179
logging.info(
"Stop run"
)
kafkaopmon.OpMonSubscriber.OpMonFunction
Definition
OpMonSubscriber.py:16
kafkaopmon.OpMonSubscriber.OpMonFunction.opmon_id
opmon_id
Definition
OpMonSubscriber.py:24
kafkaopmon.OpMonSubscriber.OpMonFunction.execute
None execute(self, entry.OpMonEntry e)
Definition
OpMonSubscriber.py:37
kafkaopmon.OpMonSubscriber.OpMonFunction.function
function
Definition
OpMonSubscriber.py:23
kafkaopmon.OpMonSubscriber.OpMonFunction.match
bool match(self, str key)
Definition
OpMonSubscriber.py:28
kafkaopmon.OpMonSubscriber.OpMonFunction.__init__
None __init__(self, Callable function, re.Pattern opmon_id, re.Pattern measurement)
Definition
OpMonSubscriber.py:21
kafkaopmon.OpMonSubscriber.OpMonFunction.measurement
measurement
Definition
OpMonSubscriber.py:25
kafkaopmon.OpMonSubscriber.OpMonSubscriber
Definition
OpMonSubscriber.py:43
kafkaopmon.OpMonSubscriber.OpMonSubscriber.bootstrap
bootstrap
Options from configurations.
Definition
OpMonSubscriber.py:55
kafkaopmon.OpMonSubscriber.OpMonSubscriber.remove_callback
bool remove_callback(self, str name)
Definition
OpMonSubscriber.py:110
kafkaopmon.OpMonSubscriber.OpMonSubscriber.start
None start(self)
Definition
OpMonSubscriber.py:125
kafkaopmon.OpMonSubscriber.OpMonSubscriber.running
bool running
runtime options
Definition
OpMonSubscriber.py:63
kafkaopmon.OpMonSubscriber.OpMonSubscriber.stop
None stop(self)
Definition
OpMonSubscriber.py:132
kafkaopmon.OpMonSubscriber.OpMonSubscriber.clear_callbacks
None clear_callbacks(self)
Definition
OpMonSubscriber.py:103
kafkaopmon.OpMonSubscriber.OpMonSubscriber.functions
dict functions
Definition
OpMonSubscriber.py:64
kafkaopmon.OpMonSubscriber.OpMonSubscriber.thread
thread
Definition
OpMonSubscriber.py:65
kafkaopmon.OpMonSubscriber.OpMonSubscriber.default_id
str default_id(self)
Definition
OpMonSubscriber.py:68
kafkaopmon.OpMonSubscriber.OpMonSubscriber.topics
topics
Definition
OpMonSubscriber.py:61
kafkaopmon.OpMonSubscriber.OpMonSubscriber.message_loop
None message_loop(self)
Definition
OpMonSubscriber.py:138
kafkaopmon.OpMonSubscriber.OpMonSubscriber.timeout
timeout
Definition
OpMonSubscriber.py:57
kafkaopmon.OpMonSubscriber.OpMonSubscriber.__init__
None __init__(self, str bootstrap, str|None group_id=None, int timeout_ms=500, dict[str, str]|None topics=None)
Definition
OpMonSubscriber.py:52
kafkaopmon.OpMonSubscriber.OpMonSubscriber.add_callback
bool add_callback(self, str name, Callable function, str opmon_id=".*", str measurement=".*")
Definition
OpMonSubscriber.py:82
kafkaopmon.OpMonSubscriber.OpMonSubscriber.group_id
group_id
Definition
OpMonSubscriber.py:56
opmonlib::opmon_entry_pb2
Generated on
for DUNE-DAQ by
1.17.0