feat(bin/logcat): support more toString formats

This commit is contained in:
Simon Chan 2023-03-21 20:38:29 +08:00
parent 82a6732e9e
commit 11011d1e85
No known key found for this signature in database
GPG key ID: A8B69F750B9BCEDD

View file

@ -68,7 +68,8 @@ export enum LogcatFormat {
} }
export interface LogcatFormatModifiers { export interface LogcatFormatModifiers {
usec?: boolean; microseconds?: boolean;
nanoseconds?: boolean;
printable?: boolean; printable?: boolean;
year?: boolean; year?: boolean;
zone?: boolean; zone?: boolean;
@ -91,14 +92,14 @@ export const LoggerEntry = new Struct({ littleEndian: true })
.uint16("headerSize") .uint16("headerSize")
.int32("pid") .int32("pid")
.uint32("tid") .uint32("tid")
.uint32("second") .uint32("seconds")
.uint32("nanoseconds") .uint32("nanoseconds")
.uint32("logId") .uint32("logId")
.uint32("uid") .uint32("uid")
.extra({ .extra({
get timestamp() { get timestamp() {
return ( return (
BigInt(this.second) * NANOSECONDS_PER_SECOND + BigInt(this.seconds) * NANOSECONDS_PER_SECOND +
BigInt(this.nanoseconds) BigInt(this.nanoseconds)
); );
}, },
@ -111,36 +112,139 @@ export interface AndroidLogEntry extends LoggerEntry {
priority: AndroidLogPriority; priority: AndroidLogPriority;
tag: string; tag: string;
message: string; message: string;
toString(format?: LogcatFormat, modifiers?: LogcatFormatModifiers): string;
} }
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=1415;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79 function secondsToTimeString(
export function formatAndroidLogEntry( seconds: number,
entry: AndroidLogEntry, modifiers: LogcatFormatModifiers
format: LogcatFormat = LogcatFormat.Brief,
modifier?: LogcatFormatModifiers
) { ) {
const uid = modifier?.uid ? `${entry.uid.toString().padStart(5)}:` : ""; if (modifiers.monotonic) {
return seconds.toString().padStart(6);
}
if (modifiers.epoch) {
return seconds.toString().padStart(19);
}
const time = new Date(seconds * 1000);
if (modifiers.year) {
// prettier-ignore
return `${
time.getFullYear().toString().padStart(4, "0")
}-${
(time.getMonth() + 1).toString().padStart(2, "0")
}-${
time.getDate().toString().padStart(2, "0")
} ${
time.getHours().toString().padStart(2, "0")
}:${
time.getMinutes().toString().padStart(2, "0")
}:${
time.getSeconds().toString().padStart(2, "0")
}`;
}
// prettier-ignore
return `${
(time.getMonth() + 1).toString().padStart(2, "0")
}-${
time.getDate().toString().padStart(2, "0")
} ${
time.getHours().toString().padStart(2, "0")
}:${
time.getMinutes().toString().padStart(2, "0")
}:${
time.getSeconds().toString().padStart(2, "0")
}`;
}
function timestampToTimeString(
seconds: number,
nanoseconds: number,
modifiers: LogcatFormatModifiers
) {
const wholePart = secondsToTimeString(seconds, modifiers);
if (modifiers.nanoseconds) {
// prettier-ignore
return `${
wholePart
}.${
nanoseconds.toString().padStart(9, "0")
}`;
}
if (modifiers.microseconds) {
// prettier-ignore
return `${
wholePart
}.${
(nanoseconds / 1000 | 0).toString().padStart(6, "0")
}`;
}
// prettier-ignore
return `${
wholePart
}.${
(nanoseconds / 1000000 | 0).toString().padStart(3, "0")
}`;
}
function entryToPrefix(
entry: AndroidLogEntry,
format: LogcatFormat,
modifiers: LogcatFormatModifiers
) {
// https://cs.android.com/android/platform/superproject/+/master:system/logging/liblog/logprint.cpp;l=1415;drc=8dbf3b2bb6b6d1652d9797e477b9abd03278bb79
const uid = modifiers?.uid ? `${entry.uid.toString().padStart(5)}` : "";
switch (format) { switch (format) {
// TODO: implement other formats // TODO: implement other formats
default: { case LogcatFormat.Brief:
// prettier-ignore // prettier-ignore
const text = `${ return `${
AndroidLogPriorityToCharacter[entry.priority] AndroidLogPriorityToCharacter[entry.priority]
}/${ }/${
entry.tag.padEnd(8) entry.tag.padEnd(8)
}(${ }(${
uid uid ? uid + ":" : ""
}${ }${
entry.pid.toString().padStart(5) entry.pid.toString().padStart(5)
}): ${ }): `;
entry.message case LogcatFormat.Raw:
}`; return "";
return text; case LogcatFormat.ThreadTime:
} default:
// prettier-ignore
return `${
timestampToTimeString(entry.seconds, entry.nanoseconds, modifiers)
} ${
uid ? uid + " " : ""
}${
entry.pid.toString().padStart(5)
} ${
entry.tid.toString().padStart(5)
} ${
AndroidLogPriorityToCharacter[entry.priority]
} ${
entry.tag.toString().padEnd(8)
}: `;
} }
} }
function AndroidLogEntryToString(
this: AndroidLogEntry,
format: LogcatFormat = LogcatFormat.ThreadTime,
modifiers: LogcatFormatModifiers = {}
) {
const prefix = entryToPrefix(this, format, modifiers);
return prefix + this.message.replaceAll("\n", "\n" + prefix);
}
function findTagEnd(payload: Uint8Array) { function findTagEnd(payload: Uint8Array) {
for (const separator of [0, " ".charCodeAt(0), ":".charCodeAt(0)]) { for (const separator of [0, " ".charCodeAt(0), ":".charCodeAt(0)]) {
const index = payload.indexOf(separator); const index = payload.indexOf(separator);
@ -179,6 +283,7 @@ export async function deserializeAndroidLogEntry(
tagEnd < payload.length - 1 tagEnd < payload.length - 1
? decodeUtf8(payload.subarray(tagEnd + 1)) ? decodeUtf8(payload.subarray(tagEnd + 1))
: ""; : "";
entry.toString = AndroidLogEntryToString;
return entry; return entry;
} }
@ -253,6 +358,7 @@ export class Logcat extends AdbCommandBase {
maxEntrySize: parseInt(match[8]!, 10), maxEntrySize: parseInt(match[8]!, 10),
maxPayloadSize: parseInt(match[9]!, 10), maxPayloadSize: parseInt(match[9]!, 10),
}); });
return;
} }
match = chunk.match(Logcat.LOG_SIZE_REGEX_10); match = chunk.match(Logcat.LOG_SIZE_REGEX_10);