Skip to content

Commit 28fb78a

Browse files
Merge pull request #215 from runpod/json-logging
Json logging
2 parents f723aa0 + b316248 commit 28fb78a

File tree

5 files changed

+70
-20
lines changed

5 files changed

+70
-20
lines changed

examples/serverless/logger.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
""" Example of using the RunPodLogger class. """""
2+
3+
import runpod
4+
5+
JOB_ID = '1234567890'
6+
log = runpod.RunPodLogger()
7+
8+
9+
log.debug('A debug message')
10+
log.info('An info message')
11+
log.warn('A warning message')
12+
log.error('An error message')
13+
14+
# Output:
15+
# DEBUG | A debug message
16+
# INFO | An info message
17+
# WARN | A warning message
18+
# ERROR | An error message
19+
20+
21+
log.debug('A debug message', job_id=JOB_ID)
22+
log.info('An info message', job_id=JOB_ID)
23+
log.warn('A warning message', job_id=JOB_ID)
24+
log.error('An error message', job_id=JOB_ID)
25+
26+
# Output:
27+
# {"requestId": "1234567890", "message": "A debug message", "level": "DEBUG"}
28+
# {"requestId": "1234567890", "message": "An info message", "level": "INFO"}
29+
# {"requestId": "1234567890", "message": "A warning message", "level": "WARN"}
30+
# {"requestId": "1234567890", "message": "An error message", "level": "ERROR"}

requirements.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ fastapi[all] >= 0.94.0
99
paramiko >= 3.3.1
1010
prettytable >= 3.9.0
1111
py-cpuinfo >= 9.0.0
12-
python-dotenv >= 1.0.0
1312
inquirerpy == 0.3.4
1413
requests >= 2.31.0
1514
tomli >= 2.0.1
1615
tomlkit >= 0.12.2
1716
tqdm-loggable >= 0.1.4
1817
urllib3 >= 1.26.6
19-
setuptools_scm >= 8.0.4
2018
watchdog >= 3.0.0

runpod/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
import logging
55

66
from . import serverless
7+
from .serverless.modules.rp_logger import RunPodLogger
78
from .endpoint import Endpoint
89
from .endpoint import AsyncioEndpoint, AsyncioJob
910
from .version import __version__
10-
from .api.ctl_commands import(
11+
from .api.ctl_commands import (
1112
get_user, update_user_settings,
1213
get_gpu, get_gpus,
1314
get_pod, get_pods, create_pod, stop_pod, resume_pod, terminate_pod,

runpod/serverless/modules/rp_logger.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@
1111
'''
1212

1313
import os
14-
from dotenv import load_dotenv
14+
import json
1515

16-
env_path = os.path.join(os.getcwd(), '.env')
17-
load_dotenv(env_path) # Load environment variables
1816

1917
LOG_LEVELS = ['NOTSET', 'DEBUG', 'INFO', 'WARN', 'ERROR']
2018

@@ -46,7 +44,8 @@ class RunPodLogger:
4644
__instance = None
4745
level = _validate_log_level(os.environ.get(
4846
'RUNPOD_LOG_LEVEL',
49-
os.environ.get('RUNPOD_DEBUG_LEVEL', 'DEBUG')))
47+
os.environ.get('RUNPOD_DEBUG_LEVEL', 'DEBUG'))
48+
)
5049

5150
def __new__(cls):
5251
if RunPodLogger.__instance is None:
@@ -61,7 +60,7 @@ def set_level(self, new_level):
6160
self.level = _validate_log_level(new_level)
6261
self.info(f'Log level set to {self.level}')
6362

64-
def log(self, message, message_level='INFO'):
63+
def log(self, message, message_level='INFO', job_id=None):
6564
'''
6665
Log message to stdout if RUNPOD_DEBUG is true.
6766
'''
@@ -72,6 +71,15 @@ def log(self, message, message_level='INFO'):
7271
if level_index > LOG_LEVELS.index(message_level) and message_level != 'TIP':
7372
return
7473

74+
if job_id:
75+
log_json = {
76+
'requestId': job_id,
77+
'message': message,
78+
'level': message_level
79+
}
80+
print(json.dumps(log_json), flush=True)
81+
return
82+
7583
print(f'{message_level.ljust(7)}| {message}', flush=True)
7684
return
7785

@@ -84,29 +92,29 @@ def secret(self, secret_name, secret):
8492
redacted_secret = secret[0] + '*' * (len(secret)-2) + secret[-1]
8593
self.info(f"{secret_name}: {redacted_secret}")
8694

87-
def debug(self, message):
95+
def debug(self, message, job_id=None):
8896
'''
8997
debug log
9098
'''
91-
self.log(message, 'DEBUG')
99+
self.log(message, 'DEBUG', job_id)
92100

93-
def info(self, message):
101+
def info(self, message, job_id=None):
94102
'''
95103
info log
96104
'''
97-
self.log(message, 'INFO')
105+
self.log(message, 'INFO', job_id)
98106

99-
def warn(self, message):
107+
def warn(self, message, job_id=None):
100108
'''
101109
warn log
102110
'''
103-
self.log(message, 'WARN')
111+
self.log(message, 'WARN', job_id)
104112

105-
def error(self, message):
113+
def error(self, message, job_id=None):
106114
'''
107115
error log
108116
'''
109-
self.log(message, 'ERROR')
117+
self.log(message, 'ERROR', job_id)
110118

111119
def tip(self, message):
112120
'''

tests/test_serverless/test_modules/test_logger.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ def test_call_log(self):
5757

5858
log.warn("Test log message")
5959

60-
mock_log.assert_called_once_with("Test log message", "WARN")
60+
mock_log.assert_called_once_with("Test log message", "WARN", None)
6161

6262
log.set_level(0)
6363
with patch("runpod.serverless.modules.rp_logger.RunPodLogger.log") as mock_log, \
64-
patch("builtins.print") as mock_print:
64+
patch("builtins.print") as mock_print:
6565

6666
log.debug("Test log message")
6767

68-
mock_log.assert_called_once_with("Test log message", "DEBUG")
68+
mock_log.assert_called_once_with("Test log message", "DEBUG", None)
6969
mock_print.assert_not_called()
7070

7171
# Reset log level
@@ -99,7 +99,7 @@ def test_log_secret(self):
9999
'''
100100
with patch("runpod.serverless.modules.rp_logger.RunPodLogger.log") as mock_log:
101101
self.logger.secret("test_secret", "test_secret_value")
102-
mock_log.assert_called_once_with("test_secret: t***************e", "INFO")
102+
mock_log.assert_called_once_with("test_secret: t***************e", "INFO", None)
103103

104104
def test_log_tip(self):
105105
'''
@@ -108,3 +108,16 @@ def test_log_tip(self):
108108
with patch("runpod.serverless.modules.rp_logger.RunPodLogger.log") as mock_log:
109109
self.logger.tip("test_tip")
110110
mock_log.assert_called_once_with("test_tip", "TIP")
111+
112+
def test_log_job_id(self):
113+
""" Tests that the log method logs a job id """
114+
logger = rp_logger.RunPodLogger()
115+
job_id = "test_job_id"
116+
117+
# Patch print to capture stdout
118+
with patch("builtins.print") as mock_print:
119+
logger.log("test_message", "INFO", job_id)
120+
mock_print.assert_called_once_with(
121+
'{"requestId": "test_job_id", "message": "test_message", "level": "INFO"}',
122+
flush=True
123+
)

0 commit comments

Comments
 (0)