Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 89118a2a authored by Simon Chan's avatar Simon Chan
Browse files

feat(bin/logcat): support all output formats

parent 4a21f00b
Loading
Loading
Loading
Loading
+86 −2
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ const state = makeAutoObservable(

        format: LogcatFormat.ThreadTime,
        formatModifierUid: false,
        formatModifierTimezone: false,
        formatTime: "default" as "year" | "default" | "epoch" | "monotonic",
        formatNanosecond: "millisecond" as
            | "millisecond"
@@ -110,6 +111,7 @@ const state = makeAutoObservable(
                monotonic: this.formatTime === "monotonic",
                microseconds: this.formatNanosecond === "microsecond",
                nanoseconds: this.formatNanosecond === "nanosecond",
                timezone: this.formatModifierTimezone,
            });
        },

@@ -267,6 +269,48 @@ const state = makeAutoObservable(
                                    this.format = LogcatFormat.Brief;
                                }),
                            },
                            {
                                key: "process",
                                text: "Process",
                                canCheck: true,
                                itemProps: {
                                    radioGroup: "format",
                                },
                                checked: this.format === LogcatFormat.Process,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.format = LogcatFormat.Process;
                                }),
                            },
                            {
                                key: "tag",
                                text: "Tag",
                                canCheck: true,
                                itemProps: {
                                    radioGroup: "format",
                                },
                                checked: this.format === LogcatFormat.Tag,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.format = LogcatFormat.Tag;
                                }),
                            },
                            {
                                key: "thread",
                                text: "Thread",
                                canCheck: true,
                                itemProps: {
                                    radioGroup: "format",
                                },
                                checked: this.format === LogcatFormat.Thread,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.format = LogcatFormat.Thread;
                                }),
                            },
                            {
                                key: "raw",
                                text: "Raw",
@@ -282,7 +326,21 @@ const state = makeAutoObservable(
                                }),
                            },
                            {
                                key: "threadTime",
                                key: "time",
                                text: "Time",
                                canCheck: true,
                                itemProps: {
                                    radioGroup: "format",
                                },
                                checked: this.format === LogcatFormat.Time,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.format = LogcatFormat.Time;
                                }),
                            },
                            {
                                key: "thread-time",
                                text: "ThreadTime",
                                canCheck: true,
                                itemProps: {
@@ -296,6 +354,20 @@ const state = makeAutoObservable(
                                    this.format = LogcatFormat.ThreadTime;
                                }),
                            },
                            {
                                key: "long",
                                text: "Long",
                                canCheck: true,
                                itemProps: {
                                    radioGroup: "format",
                                },
                                checked: this.format === LogcatFormat.Long,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.format = LogcatFormat.Long;
                                }),
                            },

                            {
                                key: "modifiers",
@@ -314,9 +386,21 @@ const state = makeAutoObservable(
                                        !this.formatModifierUid;
                                }),
                            },
                            {
                                key: "timezone",
                                text: "Timezone",
                                canCheck: true,
                                checked: this.formatModifierTimezone,
                                onClick: action((e) => {
                                    e?.preventDefault();
                                    e?.stopPropagation();
                                    this.formatModifierTimezone =
                                        !this.formatModifierTimezone;
                                }),
                            },

                            {
                                key: "time",
                                key: "time-header",
                                text: "Time Format",
                                itemType: ContextualMenuItemType.Header,
                            },
+146 −48
Original line number Diff line number Diff line
@@ -72,7 +72,7 @@ export interface LogcatFormatModifiers {
    nanoseconds?: boolean;
    printable?: boolean;
    year?: boolean;
    zone?: boolean;
    timezone?: boolean;
    epoch?: boolean;
    monotonic?: boolean;
    uid?: boolean;
@@ -116,10 +116,7 @@ export interface AndroidLogEntry extends LoggerEntry {
    toString(format?: LogcatFormat, modifiers?: LogcatFormatModifiers): string;
}

function secondsToTimeString(
    seconds: number,
    modifiers: LogcatFormatModifiers
) {
function formatSeconds(seconds: number, modifiers: LogcatFormatModifiers) {
    if (modifiers.monotonic) {
        return seconds.toString().padStart(6);
    }
@@ -128,102 +125,151 @@ function secondsToTimeString(
        return seconds.toString().padStart(19);
    }

    const time = new Date(seconds * 1000);
    const date = new Date(seconds * 1000);

    if (modifiers.year) {
        // prettier-ignore
        return `${
            time.getFullYear().toString().padStart(4, "0")
            date.getFullYear().toString().padStart(4, "0")
        }-${
            (time.getMonth() + 1).toString().padStart(2, "0")
            (date.getMonth() + 1).toString().padStart(2, "0")
        }-${
            time.getDate().toString().padStart(2, "0")
            date.getDate().toString().padStart(2, "0")
        } ${
            time.getHours().toString().padStart(2, "0")
            date.getHours().toString().padStart(2, "0")
        }:${
            time.getMinutes().toString().padStart(2, "0")
            date.getMinutes().toString().padStart(2, "0")
        }:${
            time.getSeconds().toString().padStart(2, "0")
            date.getSeconds().toString().padStart(2, "0")
        }`;
    }

    // prettier-ignore
    return `${
        (time.getMonth() + 1).toString().padStart(2, "0")
        (date.getMonth() + 1).toString().padStart(2, "0")
    }-${
        time.getDate().toString().padStart(2, "0")
        date.getDate().toString().padStart(2, "0")
    } ${
        time.getHours().toString().padStart(2, "0")
        date.getHours().toString().padStart(2, "0")
    }:${
        time.getMinutes().toString().padStart(2, "0")
        date.getMinutes().toString().padStart(2, "0")
    }:${
        time.getSeconds().toString().padStart(2, "0")
        date.getSeconds().toString().padStart(2, "0")
    }`;
}

function timestampToTimeString(
    seconds: number,
function formatNanoseconds(
    nanoseconds: number,
    modifiers: LogcatFormatModifiers
) {
    const wholePart = secondsToTimeString(seconds, modifiers);

    if (modifiers.nanoseconds) {
        // prettier-ignore
        return `${
            wholePart
        }.${
            nanoseconds.toString().padStart(9, "0")
        }`;
        return nanoseconds.toString().padStart(9, "0");
    }

    if (modifiers.microseconds) {
        // prettier-ignore
        return `${
            wholePart
        }.${
            (nanoseconds / 1000 | 0).toString().padStart(6, "0")
        }`;
        return ((nanoseconds / 1000) | 0).toString().padStart(6, "0");
    }

    return ((nanoseconds / 1000000) | 0).toString().padStart(3, "0");
}

function formatTimezone(seconds: number, modifiers: LogcatFormatModifiers) {
    if (!modifiers.timezone || modifiers.monotonic || modifiers.epoch) {
        return "";
    }

    const date = new Date(seconds * 1000);
    const offset = date.getTimezoneOffset();
    const sign = offset <= 0 ? "+" : "-";
    const absolute = Math.abs(offset);
    const hours = (absolute / 60) | 0;
    const minutes = absolute % 60;

    // prettier-ignore
    return ` ${
        wholePart
    }.${
        (nanoseconds / 1000000 | 0).toString().padStart(3, "0")
        sign
    }${
        hours.toString().padStart(2, "0")
    }:${
        minutes.toString().padStart(2, "0")
    }`;
}

function entryToPrefix(
function formatTime(
    seconds: number,
    nanoseconds: number,
    modifiers: LogcatFormatModifiers
) {
    const secondsString = formatSeconds(seconds, modifiers);
    const nanosecondsString = formatNanoseconds(nanoseconds, modifiers);
    const zoneString = formatTimezone(seconds, modifiers);
    return `${secondsString}.${nanosecondsString}${zoneString}`;
}

function formatUid(
    uid: number,
    modifiers: LogcatFormatModifiers,
    suffix: string
) {
    return modifiers.uid ? `${uid.toString().padStart(5)}${suffix}` : "";
}

function getFormatPrefix(
    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) {
        // TODO: implement other formats
        case LogcatFormat.Brief:
        case LogcatFormat.Tag:
            // prettier-ignore
            return `${
                AndroidLogPriorityToCharacter[entry.priority]
            }/${
                entry.tag.padEnd(8)
            }: `;
        case LogcatFormat.Process:
            // prettier-ignore
            return `${
                AndroidLogPriorityToCharacter[entry.priority]
            }(${
                uid ? uid + ":" : ""
                formatUid(entry.uid, modifiers, ":")
            }${
                entry.pid.toString().padStart(5)
            }): `;
            }) `;
        case LogcatFormat.Thread:
            // prettier-ignore
            return `${
                AndroidLogPriorityToCharacter[entry.priority]
            }(${
                formatUid(entry.uid, modifiers, ":")
            }${
                entry.pid.toString().padStart(5)
            }:${
                entry.tid.toString().padStart(5)
            }) `;
        case LogcatFormat.Raw:
            return "";
        case LogcatFormat.Time:
            // prettier-ignore
            return `${
                formatTime(entry.seconds, entry.nanoseconds, modifiers)
            } ${
                AndroidLogPriorityToCharacter[entry.priority]
            }/${
                entry.tag.padEnd(8)
            }(${
                formatUid(entry.uid, modifiers, ":")
            }${
                entry.pid.toString().padStart(5)
            }): `;
        case LogcatFormat.ThreadTime:
        default:
            // prettier-ignore
            return `${
                timestampToTimeString(entry.seconds, entry.nanoseconds, modifiers)
                formatTime(entry.seconds, entry.nanoseconds, modifiers)
            } ${
                uid ? uid + " " : ""
                formatUid(entry.uid, modifiers, " ")
            }${
                entry.pid.toString().padStart(5)
            } ${
@@ -233,7 +279,40 @@ function entryToPrefix(
            } ${
                entry.tag.toString().padEnd(8)
            }: `;
        case LogcatFormat.Brief:
        default:
            // prettier-ignore
            return `${
                AndroidLogPriorityToCharacter[entry.priority]
            }/${
                entry.tag.padEnd(8)
            }(${
                formatUid(entry.uid, modifiers, ":")
            }${
                entry.pid.toString().padStart(5)
            }): `;
    }
}

function getFormatSuffix(entry: AndroidLogEntry, format: LogcatFormat) {
    switch (format) {
        case LogcatFormat.Process:
            return `  (${entry.tag})`;
        default:
            return "";
    }
}

function formatEntryWrapLine(
    entry: AndroidLogEntry,
    format: LogcatFormat,
    modifiers: LogcatFormatModifiers
) {
    const prefix = getFormatPrefix(entry, format, modifiers);
    const suffix = getFormatSuffix(entry, format);
    return (
        prefix + entry.message.replaceAll("\n", suffix + "\n" + prefix) + suffix
    );
}

function AndroidLogEntryToString(
@@ -241,8 +320,27 @@ function AndroidLogEntryToString(
    format: LogcatFormat = LogcatFormat.ThreadTime,
    modifiers: LogcatFormatModifiers = {}
) {
    const prefix = entryToPrefix(this, format, modifiers);
    return prefix + this.message.replaceAll("\n", "\n" + prefix);
    switch (format) {
        case LogcatFormat.Long:
            // prettier-ignore
            return `[ ${
                formatTime(this.seconds, this.nanoseconds, modifiers)
            } ${
                formatUid(this.uid, modifiers, ":")
            }${
                this.pid.toString().padStart(5)
            }:${
                this.tid.toString().padStart(5)
            } ${
                AndroidLogPriorityToCharacter[this.priority]
            }/${
                this.tag.padEnd(8)
            } ]\n${
                this.message
            }\n`;
        default:
            return formatEntryWrapLine(this, format, modifiers);
    }
}

function findTagEnd(payload: Uint8Array) {