Skip to content

Commit b51fee5

Browse files
authored
Add: application performance monitoring via Honeycomb (#20)
If you don't have "honeycomb-beeline" package installed, it doesn't do anything. If you do have it installed, it ensure all important functions are traced. By default, this library creates a new trace for each new incoming packet. For all other cases it is up to the application to make good traces out of this.
1 parent 5c1a29c commit b51fee5

File tree

7 files changed

+86
-6
lines changed

7 files changed

+86
-6
lines changed

openttd_protocol/protocol/content.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
import struct
44

5+
from .. import tracer
56
from ..wire.exceptions import PacketInvalidData
67
from ..wire.read import (
78
read_string,
@@ -71,6 +72,7 @@ class ContentProtocol(TCPProtocol):
7172
PACKET_END = PacketContentType.PACKET_CONTENT_END
7273

7374
@staticmethod
75+
@tracer.traced("content")
7476
def receive_PACKET_CONTENT_CLIENT_INFO_LIST(source, data):
7577
content_type, data = read_uint8(data)
7678
openttd_version, data = read_uint32(data)
@@ -141,6 +143,7 @@ def _receive_client_info(data, count, has_content_id=False, has_content_type_and
141143
return content_infos, data
142144

143145
@classmethod
146+
@tracer.traced("content")
144147
def receive_PACKET_CONTENT_CLIENT_INFO_ID(cls, source, data):
145148
count, data = read_uint16(data)
146149

@@ -152,6 +155,7 @@ def receive_PACKET_CONTENT_CLIENT_INFO_ID(cls, source, data):
152155
return {"content_infos": content_infos}
153156

154157
@classmethod
158+
@tracer.traced("content")
155159
def receive_PACKET_CONTENT_CLIENT_INFO_EXTID(cls, source, data):
156160
count, data = read_uint8(data)
157161

@@ -163,6 +167,7 @@ def receive_PACKET_CONTENT_CLIENT_INFO_EXTID(cls, source, data):
163167
return {"content_infos": content_infos}
164168

165169
@classmethod
170+
@tracer.traced("content")
166171
def receive_PACKET_CONTENT_CLIENT_INFO_EXTID_MD5(cls, source, data):
167172
count, data = read_uint8(data)
168173

@@ -176,6 +181,7 @@ def receive_PACKET_CONTENT_CLIENT_INFO_EXTID_MD5(cls, source, data):
176181
return {"content_infos": content_infos}
177182

178183
@classmethod
184+
@tracer.traced("content")
179185
def receive_PACKET_CONTENT_CLIENT_CONTENT(cls, source, data):
180186
count, data = read_uint16(data)
181187

@@ -186,6 +192,7 @@ def receive_PACKET_CONTENT_CLIENT_CONTENT(cls, source, data):
186192

187193
return {"content_infos": content_infos}
188194

195+
@tracer.traced("content")
189196
async def send_PACKET_CONTENT_SERVER_INFO(
190197
self, content_type, content_id, filesize, name, version, url, description, unique_id, md5sum, dependencies, tags
191198
):
@@ -227,6 +234,7 @@ async def send_PACKET_CONTENT_SERVER_INFO(
227234
write_presend(data, SEND_TCP_COMPAT_MTU)
228235
await self.send_packet(data)
229236

237+
@tracer.traced("content")
230238
async def send_PACKET_CONTENT_SERVER_CONTENT(self, content_type, content_id, filesize, filename, stream):
231239
# First, send a packet to tell the client it will be receiving a file
232240
data = write_init(PacketContentType.PACKET_CONTENT_SERVER_CONTENT)

openttd_protocol/protocol/coordinator.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import enum
22
import logging
33

4+
from .. import tracer
45
from ..wire.exceptions import PacketInvalidData
56
from ..wire.read import (
67
read_bytes,
@@ -94,6 +95,7 @@ class CoordinatorProtocol(TCPProtocol):
9495
PACKET_END = PacketCoordinatorType.PACKET_COORDINATOR_END
9596

9697
@staticmethod
98+
@tracer.traced("coordinator")
9799
def receive_PACKET_COORDINATOR_SERVER_REGISTER(source, data):
98100
protocol_version, data = read_uint8(data)
99101

@@ -128,6 +130,7 @@ def receive_PACKET_COORDINATOR_SERVER_REGISTER(source, data):
128130
}
129131

130132
@staticmethod
133+
@tracer.traced("coordinator")
131134
def receive_PACKET_COORDINATOR_SERVER_UPDATE(source, data):
132135
protocol_version, data = read_uint8(data)
133136

@@ -240,6 +243,7 @@ def receive_PACKET_COORDINATOR_SERVER_UPDATE(source, data):
240243
}
241244

242245
@staticmethod
246+
@tracer.traced("coordinator")
243247
def receive_PACKET_COORDINATOR_CLIENT_LISTING(source, data):
244248
protocol_version, data = read_uint8(data)
245249

@@ -268,6 +272,7 @@ def receive_PACKET_COORDINATOR_CLIENT_LISTING(source, data):
268272
}
269273

270274
@staticmethod
275+
@tracer.traced("coordinator")
271276
def receive_PACKET_COORDINATOR_CLIENT_CONNECT(source, data):
272277
protocol_version, data = read_uint8(data)
273278

@@ -285,6 +290,7 @@ def receive_PACKET_COORDINATOR_CLIENT_CONNECT(source, data):
285290
}
286291

287292
@staticmethod
293+
@tracer.traced("coordinator")
288294
def receive_PACKET_COORDINATOR_SERCLI_CONNECT_FAILED(source, data):
289295
protocol_version, data = read_uint8(data)
290296

@@ -304,6 +310,7 @@ def receive_PACKET_COORDINATOR_SERCLI_CONNECT_FAILED(source, data):
304310
}
305311

306312
@staticmethod
313+
@tracer.traced("coordinator")
307314
def receive_PACKET_COORDINATOR_CLIENT_CONNECTED(source, data):
308315
protocol_version, data = read_uint8(data)
309316

@@ -321,6 +328,7 @@ def receive_PACKET_COORDINATOR_CLIENT_CONNECTED(source, data):
321328
}
322329

323330
@staticmethod
331+
@tracer.traced("coordinator")
324332
def receive_PACKET_COORDINATOR_SERCLI_STUN_RESULT(source, data):
325333
protocol_version, data = read_uint8(data)
326334

@@ -341,6 +349,7 @@ def receive_PACKET_COORDINATOR_SERCLI_STUN_RESULT(source, data):
341349
"result": result,
342350
}
343351

352+
@tracer.traced("coordinator")
344353
async def send_PACKET_COORDINATOR_GC_ERROR(self, protocol_version, error_no, error_detail):
345354
data = write_init(PacketCoordinatorType.PACKET_COORDINATOR_GC_ERROR)
346355

@@ -358,6 +367,7 @@ async def send_PACKET_COORDINATOR_GC_ERROR(self, protocol_version, error_no, err
358367
write_presend(data, SEND_TCP_MTU)
359368
await self.send_packet(data)
360369

370+
@tracer.traced("coordinator")
361371
async def send_PACKET_COORDINATOR_GC_REGISTER_ACK(
362372
self, protocol_version, connection_type, invite_code, invite_code_secret
363373
):
@@ -396,6 +406,7 @@ def _fill_NEWGRF_LOOKUP_PACKET(self, newgrf_lookup_table_cursor, newgrf_lookup_t
396406
if count != 0:
397407
yield count, data
398408

409+
@tracer.traced("coordinator")
399410
async def send_PACKET_COORDINATOR_GC_NEWGRF_LOOKUP(
400411
self, protocol_version, newgrf_lookup_table_cursor, newgrf_lookup_table
401412
):
@@ -413,6 +424,7 @@ async def send_PACKET_COORDINATOR_GC_NEWGRF_LOOKUP(
413424
write_presend(data, SEND_TCP_MTU)
414425
await self.send_packet(data)
415426

427+
@tracer.traced("coordinator")
416428
async def send_PACKET_COORDINATOR_GC_LISTING(
417429
self, protocol_version, game_info_version, servers, newgrf_lookup_table
418430
):
@@ -491,6 +503,7 @@ async def send_PACKET_COORDINATOR_GC_LISTING(
491503
write_presend(data, SEND_TCP_MTU)
492504
await self.send_packet(data)
493505

506+
@tracer.traced("coordinator")
494507
async def send_PACKET_COORDINATOR_GC_CONNECTING(self, protocol_version, token, invite_code):
495508
data = write_init(PacketCoordinatorType.PACKET_COORDINATOR_GC_CONNECTING)
496509

@@ -500,6 +513,7 @@ async def send_PACKET_COORDINATOR_GC_CONNECTING(self, protocol_version, token, i
500513
write_presend(data, SEND_TCP_MTU)
501514
await self.send_packet(data)
502515

516+
@tracer.traced("coordinator")
503517
async def send_PACKET_COORDINATOR_GC_CONNECT_FAILED(self, protocol_version, token):
504518
data = write_init(PacketCoordinatorType.PACKET_COORDINATOR_GC_CONNECT_FAILED)
505519

@@ -508,6 +522,7 @@ async def send_PACKET_COORDINATOR_GC_CONNECT_FAILED(self, protocol_version, toke
508522
write_presend(data, SEND_TCP_MTU)
509523
await self.send_packet(data)
510524

525+
@tracer.traced("coordinator")
511526
async def send_PACKET_COORDINATOR_GC_DIRECT_CONNECT(self, protocol_version, token, tracking_number, hostname, port):
512527
data = write_init(PacketCoordinatorType.PACKET_COORDINATOR_GC_DIRECT_CONNECT)
513528

@@ -519,6 +534,7 @@ async def send_PACKET_COORDINATOR_GC_DIRECT_CONNECT(self, protocol_version, toke
519534
write_presend(data, SEND_TCP_MTU)
520535
await self.send_packet(data)
521536

537+
@tracer.traced("coordinator")
522538
async def send_PACKET_COORDINATOR_GC_STUN_REQUEST(self, protocol_version, token):
523539
data = write_init(PacketCoordinatorType.PACKET_COORDINATOR_GC_STUN_REQUEST)
524540

@@ -527,6 +543,7 @@ async def send_PACKET_COORDINATOR_GC_STUN_REQUEST(self, protocol_version, token)
527543
write_presend(data, SEND_TCP_MTU)
528544
await self.send_packet(data)
529545

546+
@tracer.traced("coordinator")
530547
async def send_PACKET_COORDINATOR_GC_STUN_CONNECT(
531548
self, protocol_version, token, tracking_number, interface_number, hostname, port
532549
):
@@ -541,6 +558,7 @@ async def send_PACKET_COORDINATOR_GC_STUN_CONNECT(
541558
write_presend(data, SEND_TCP_MTU)
542559
await self.send_packet(data)
543560

561+
@tracer.traced("coordinator")
544562
async def send_PACKET_COORDINATOR_GC_TURN_CONNECT(
545563
self, protocol_version, token, tracking_number, ticket, connection_string
546564
):

openttd_protocol/protocol/game.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import enum
22
import logging
33

4+
from .. import tracer
45
from ..wire.exceptions import PacketInvalidData
56
from ..wire.read import (
67
read_bytes,
@@ -53,6 +54,7 @@ class GameProtocol(TCPProtocol):
5354
PACKET_END = PacketGameType.PACKET_END
5455

5556
@staticmethod
57+
@tracer.traced("game")
5658
def receive_PACKET_SERVER_GAME_INFO(source, data):
5759
game_info_version, data = read_uint8(data)
5860

@@ -158,12 +160,14 @@ def receive_PACKET_SERVER_GAME_INFO(source, data):
158160
}
159161

160162
@staticmethod
163+
@tracer.traced("game")
161164
def receive_PACKET_SERVER_SHUTDOWN(source, data):
162165
if len(data) != 0:
163166
raise PacketInvalidData("more bytes than expected in SERVER_SHUTDOWN; remaining: ", len(data))
164167

165168
return {}
166169

170+
@tracer.traced("game")
167171
async def send_PACKET_CLIENT_GAME_INFO(self):
168172
data = write_init(PacketGameType.PACKET_CLIENT_GAME_INFO)
169173
write_presend(data, SEND_TCP_MTU)

openttd_protocol/protocol/stun.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import enum
22
import logging
33

4+
from .. import tracer
45
from ..wire.exceptions import PacketInvalidData
56
from ..wire.read import (
67
read_string,
@@ -21,6 +22,7 @@ class StunProtocol(TCPProtocol):
2122
PACKET_END = PacketStunType.PACKET_STUN_END
2223

2324
@staticmethod
25+
@tracer.traced("stun")
2426
def receive_PACKET_STUN_SERCLI_STUN(source, data):
2527
protocol_version, data = read_uint8(data)
2628

openttd_protocol/protocol/turn.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import enum
22
import logging
33

4+
from .. import tracer
45
from ..wire.exceptions import PacketInvalidData
56
from ..wire.read import (
67
read_string,
@@ -29,6 +30,7 @@ class TurnProtocol(TCPProtocol):
2930
PACKET_END = PacketTurnType.PACKET_TURN_END
3031

3132
@staticmethod
33+
@tracer.traced("turn")
3234
def receive_PACKET_TURN_SERCLI_CONNECT(source, data):
3335
protocol_version, data = read_uint8(data)
3436

@@ -42,6 +44,7 @@ def receive_PACKET_TURN_SERCLI_CONNECT(source, data):
4244

4345
return {"protocol_version": protocol_version, "ticket": ticket}
4446

47+
@tracer.traced("turn")
4548
async def send_PACKET_TURN_TURN_CONNECTED(self, protocol_version, hostname):
4649
data = write_init(PacketTurnType.PACKET_TURN_TURN_CONNECTED)
4750

openttd_protocol/tracer.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
try:
2+
import beeline
3+
4+
def traced(prefix):
5+
# The common case is to use the function-name, so automate this.
6+
def wrapper(func):
7+
return beeline.traced_impl(beeline.tracer, f"{prefix}.{func.__name__}", None, None)(func)
8+
9+
return wrapper
10+
11+
tracer = beeline.tracer
12+
untraced = beeline.untraced
13+
add_context = beeline.add_context
14+
15+
except ImportError:
16+
# Honeycomb Beeline package is not installed. Mock the tracer functions.
17+
18+
def traced(prefix):
19+
def wrapper(func):
20+
return func
21+
22+
return wrapper
23+
24+
class tracer:
25+
def __init__(self, name):
26+
pass
27+
28+
def __enter__(self):
29+
pass
30+
31+
def __exit__(self, type, value, traceback):
32+
pass
33+
34+
def untraced(func):
35+
return func
36+
37+
def add_context(payload):
38+
pass

openttd_protocol/wire/tcp.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
read_uint16,
1515
)
1616
from .source import Source
17+
from .. import tracer
1718

1819
log = logging.getLogger(__name__)
1920

@@ -173,14 +174,19 @@ async def _process_queue(self):
173174
if await self._callback.receive_raw(self.source, data):
174175
return
175176

176-
try:
177-
packet_type, kwargs = self.receive_packet(self.source, data)
178-
except PacketInvalid as err:
179-
log.info("Dropping invalid packet from %s:%d: %r", self.source.ip, self.source.port, err)
180-
raise SocketClosed
177+
with tracer.tracer("tcp.receive-packet"):
178+
try:
179+
packet_type, kwargs = self.receive_packet(self.source, data)
180+
except PacketInvalid as err:
181+
log.info("Dropping invalid packet from %s:%d: %r", self.source.ip, self.source.port, err)
182+
raise SocketClosed
183+
184+
tracer.add_context({"command": f"receive.{packet_type.name}"})
181185

182-
await getattr(self._callback, f"receive_{packet_type.name}")(self.source, **kwargs)
186+
with tracer.tracer("tcp.packet-handler"):
187+
await getattr(self._callback, f"receive_{packet_type.name}")(self.source, **kwargs)
183188

189+
@tracer.traced("tcp")
184190
def receive_packet(self, source, data):
185191
# Check length of packet
186192
length, data = read_uint16(data)
@@ -202,6 +208,7 @@ def receive_packet(self, source, data):
202208
kwargs = func(source, data)
203209
return type, kwargs
204210

211+
@tracer.traced("tcp")
205212
async def send_packet(self, data):
206213
await self._can_write.wait()
207214

0 commit comments

Comments
 (0)