Skip to content

Commit 00a3c91

Browse files
author
Lukas Wingerberg
committed
add some prometheus metrics
1 parent d368c8c commit 00a3c91

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ grpcio
22
grpcio-tools
33
aiofiles
44
aiohttp
5-
pymediainfo
5+
pymediainfo
6+
prometheus_client

server/grpc-ffmpeg.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
import ffmpeg_pb2
1515
import ffmpeg_pb2_grpc
1616

17+
from prometheus_client import Gauge, Counter, make_asgi_app
18+
from prometheus_client import start_http_server as start_prometheus_server
19+
1720
# Required for MediaInfo and ffmpeg health check
1821
import aiofiles
1922
from pymediainfo import MediaInfo
@@ -37,6 +40,11 @@
3740
# Variable to store health status
3841
health_status = {'healthy': False}
3942

43+
# Prometheus metrics
44+
ffmpeg_gauge = Gauge('ffmpeg_processes', 'Number of running ffmpeg processes')
45+
mediainfo_counter = Counter('mediainfo_commands', 'Number of mediainfo commands executed')
46+
ffprobe_counter = Counter('ffprobe_commands', 'Number of ffprobe commands executed')
47+
4048
class TokenAuthValidator(grpc.AuthMetadataPlugin):
4149
def __call__(self, context, callback):
4250
token = None
@@ -69,6 +77,17 @@ async def ExecuteCommand(self, request, context):
6977
# Reconstruct the command
7078
command = shlex.join(tokens)
7179

80+
# Track metrics for this command but dont include health check commands
81+
binary = tokens[0].split('/')[-1]
82+
exclude_health_check = binary == 'ffmpeg' and HEALTHCHECK_FILE in command
83+
84+
if binary == 'ffmpeg' and not exclude_health_check:
85+
ffmpeg_gauge.inc()
86+
elif binary == 'mediainfo':
87+
mediainfo_counter.inc()
88+
elif binary == 'ffprobe':
89+
ffprobe_counter.inc()
90+
7291
process = await asyncio.create_subprocess_shell(
7392
command,
7493
stdout=asyncio.subprocess.PIPE,
@@ -90,6 +109,11 @@ async def read_stream(stream, response_type, stream_name):
90109
yield response
91110

92111
await process.wait()
112+
113+
# decrease counter whenever ffmpeg processes complete
114+
if binary == 'ffmpeg' and not exclude_health_check:
115+
ffmpeg_gauge.dec()
116+
93117
exit_code = process.returncode
94118
yield ffmpeg_pb2.CommandResponse(exit_code=exit_code, stream="exit_code")
95119

@@ -110,6 +134,7 @@ async def run_health_check(self):
110134
logger.error(f"MediaInfo failed for {HEALTHCHECK_FILE}")
111135
self.update_health_status(False)
112136
return
137+
113138
except asyncio.CancelledError:
114139
logger.info("Health check task canceled.")
115140
raise
@@ -120,6 +145,7 @@ async def run_health_check(self):
120145
# Run ffmpeg conversion test
121146
ffmpeg_command = f"{BINARY_PATH_PREFIX}ffmpeg -i {HEALTHCHECK_FILE} {HEALTHCHECK_OUTPUT}"
122147
ffmpeg_output = await self.run_command(ffmpeg_command)
148+
123149
if "Conversion failed" in ffmpeg_output:
124150
logger.error("FFmpeg conversion test failed")
125151
self.update_health_status(False)
@@ -138,14 +164,26 @@ def update_health_status(self, is_healthy):
138164
global health_status
139165
health_status['healthy'] = is_healthy
140166

141-
async def run_command(self, command):
167+
async def run_command(self, command, exclude_health_check=False):
168+
binary = command.split()[0].split('/')[-1]
169+
if binary == 'ffmpeg' and not exclude_health_check:
170+
ffmpeg_gauge.inc()
171+
elif binary == 'mediainfo':
172+
mediainfo_counter.inc()
173+
elif binary == 'ffprobe':
174+
ffprobe_counter.inc()
175+
142176
process = await asyncio.create_subprocess_shell(
143177
command,
144178
stdout=asyncio.subprocess.PIPE,
145179
stderr=asyncio.subprocess.PIPE
146180
)
147181

148182
stdout, stderr = await process.communicate()
183+
184+
if binary == 'ffmpeg' and not exclude_health_check:
185+
ffmpeg_gauge.dec()
186+
149187
output = stdout.decode().strip() if stdout else ""
150188
error = stderr.decode().strip() if stderr else ""
151189

@@ -199,8 +237,11 @@ async def health_check(request):
199237
else:
200238
return web.Response(text="Health check failed", status=500)
201239

240+
prometheus_app = make_asgi_app()
202241
app = web.Application()
203242
app.router.add_get('/health', health_check)
243+
app.router.add_route('*', '/metrics', web._run_app(prometheus_app))
244+
204245
runner = web.AppRunner(app)
205246
await runner.setup()
206247
site = web.TCPSite(runner, '0.0.0.0', 8080)

0 commit comments

Comments
 (0)