Fix the request loggings to make it fully able to be easily replayed (#2973)
This commit is contained in:
@@ -27,6 +27,7 @@ import requests
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--url", type=str, default="http://localhost:30000")
|
||||
parser.add_argument("--log-requests", action="store_true")
|
||||
parser.add_argument(
|
||||
"--dump-requests-folder", type=str, default="/tmp/sglang_request_dump"
|
||||
)
|
||||
@@ -36,6 +37,8 @@ if __name__ == "__main__":
|
||||
response = requests.post(
|
||||
args.url + "/configure_logging",
|
||||
json={
|
||||
"log_requests": args.log_requests,
|
||||
"log_requests_level": 1, # Log full requests
|
||||
"dump_requests_folder": args.dump_requests_folder,
|
||||
"dump_requests_threshold": args.dump_requests_threshold,
|
||||
},
|
||||
|
||||
@@ -495,6 +495,7 @@ class ProfileReq(Enum):
|
||||
@dataclass
|
||||
class ConfigureLoggingReq:
|
||||
log_requests: Optional[bool] = None
|
||||
log_requests_level: Optional[int] = None
|
||||
dump_requests_folder: Optional[str] = None
|
||||
dump_requests_threshold: Optional[int] = None
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ class TokenizerManager:
|
||||
self.server_args = server_args
|
||||
self.enable_metrics = server_args.enable_metrics
|
||||
self.log_requests = server_args.log_requests
|
||||
self.log_requests_level = 0
|
||||
|
||||
# Init inter-process communication
|
||||
context = zmq.asyncio.Context(2)
|
||||
@@ -276,7 +277,10 @@ class TokenizerManager:
|
||||
obj.normalize_batch_and_arguments()
|
||||
|
||||
if self.log_requests:
|
||||
logger.info(f"Receive: obj={dataclass_to_string_truncated(obj)}")
|
||||
max_length = 2048 if self.log_requests_level == 0 else 1 << 30
|
||||
logger.info(
|
||||
f"Receive: obj={dataclass_to_string_truncated(obj, max_length)}"
|
||||
)
|
||||
|
||||
async with self.model_update_lock.reader_lock:
|
||||
is_single = obj.is_single
|
||||
@@ -419,7 +423,8 @@ class TokenizerManager:
|
||||
state.out_list = []
|
||||
if state.finished:
|
||||
if self.log_requests:
|
||||
msg = f"Finish: obj={dataclass_to_string_truncated(obj)}, out={dataclass_to_string_truncated(out)}"
|
||||
max_length = 2048 if self.log_requests_level == 0 else 1 << 30
|
||||
msg = f"Finish: obj={dataclass_to_string_truncated(obj, max_length)}, out={dataclass_to_string_truncated(out, max_length)}"
|
||||
logger.info(msg)
|
||||
del self.rid_to_state[obj.rid]
|
||||
|
||||
@@ -682,6 +687,8 @@ class TokenizerManager:
|
||||
def configure_logging(self, obj: ConfigureLoggingReq):
|
||||
if obj.log_requests is not None:
|
||||
self.log_requests = obj.log_requests
|
||||
if obj.log_requests_level is not None:
|
||||
self.log_requests_level = obj.log_requests_level
|
||||
if obj.dump_requests_folder is not None:
|
||||
self.dump_requests_folder = obj.dump_requests_folder
|
||||
if obj.dump_requests_threshold is not None:
|
||||
|
||||
@@ -1262,9 +1262,9 @@ def dataclass_to_string_truncated(data, max_length=2048):
|
||||
if isinstance(data, str):
|
||||
if len(data) > max_length:
|
||||
half_length = max_length // 2
|
||||
return f'"{data[:half_length]} ... {data[-half_length:]}"'
|
||||
return f"{repr(data[:half_length])} ... {repr(data[-half_length:])}"
|
||||
else:
|
||||
return f'"{data}"'
|
||||
return f"{repr(data)}"
|
||||
elif isinstance(data, (list, tuple)):
|
||||
if len(data) > max_length:
|
||||
half_length = max_length // 2
|
||||
@@ -1275,7 +1275,7 @@ def dataclass_to_string_truncated(data, max_length=2048):
|
||||
return (
|
||||
"{"
|
||||
+ ", ".join(
|
||||
f"{k}: {dataclass_to_string_truncated(v, max_length)}"
|
||||
f"'{k}': {dataclass_to_string_truncated(v, max_length)}"
|
||||
for k, v in data.items()
|
||||
)
|
||||
+ "}"
|
||||
|
||||
Reference in New Issue
Block a user