Skip to content

Commit 717c360

Browse files
rigor789edusperoni
authored andcommitted
feat(ios): show the app's forwarded stdout and stderr
Debug builds ask the runtime to forward stdout and stderr through forwardStdio in the app's package.json. They arrive under the org.nativescript.stdio subsystem and show from --log debug, like the rest of the app's native output and as Xcode's console does, labeled with their stream.
1 parent e9a3bd7 commit 717c360

7 files changed

Lines changed: 58 additions & 2 deletions

File tree

‎docs/man_pages/project/testing/run-ios.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Start an emulator with specified device identifier and sdk | `$ ns run ios [--de
3333
* `--emulator` - If set, runs the app in all available and configured ios simulators. It will start a simulator if none are already running.
3434
* `--sdk` - Specifies the target simulator's sdk.
3535
* `--justlaunch` - If set, does not print the application output in the console.
36-
* `--log <Level>` - Also controls how much of the application output is printed. By default only its JavaScript output is shown. `debug` adds everything else the app logs - its native code and the system frameworks it uses, like Xcode's console - and `trace` adds debug level entries as well.
36+
* `--log <Level>` - Also controls how much of the application output is printed. By default only its JavaScript output is shown. `debug` adds everything else the app logs - its native code, `print()` output and the system frameworks it uses, like Xcode's console - and `trace` adds debug level entries as well.
3737
* `--clean` - If set, forces the complete rebuild of the native application.
3838
* `--no-watch` - If set, changes in your code will not be reflected during the execution of this command.
3939
* `--release` - If set, produces a release build by running webpack in production mode and native build in release mode. Otherwise, produces a debug build.

‎lib/common/definitions/mobile.d.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ declare global {
173173
image: string;
174174
level: string;
175175
message: string;
176+
subsystem?: string;
177+
category?: string;
176178
}
177179

178180
interface IiOSLogStreamOptions {

‎lib/common/mobile/ios/ios-log-entry.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export function isIOSRuntimeLogEntry(entry: Mobile.IiOSLogEntry): boolean {
3838
return path.basename(entry.image || "") === "NativeScript";
3939
}
4040

41+
// The runtime forwards the app's stdout and stderr under this subsystem, when
42+
// the CLI asks for it through the forwardStdio key of the app's package.json.
43+
const STDIO_SUBSYSTEM = "org.nativescript.stdio";
44+
4145
// Logged by the runtime itself on every launch, not by the app.
4246
const RUNTIME_NOISE = ["NativeScript loaded bundle"];
4347

@@ -57,6 +61,10 @@ export function getIOSLogEntryText(
5761
return null;
5862
}
5963

64+
if (entry.subsystem === STDIO_SUBSYSTEM) {
65+
return options.includeNative ? `${entry.category}: ${entry.message}` : null;
66+
}
67+
6068
const imageName = path.basename(entry.image || "");
6169
if (isIOSRuntimeLogEntry(entry)) {
6270
return RUNTIME_NOISE.some((noise) => entry.message.includes(noise))

‎lib/common/mobile/ios/simulator/ios-simulator-log-provider.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ export class IOSSimulatorLogProvider
143143
image: event.senderImagePath,
144144
level: (event.messageType || "").toLowerCase(),
145145
message: event.eventMessage,
146+
subsystem: event.subsystem,
147+
category: event.category,
146148
},
147149
this.$devicePlatformsConstants.iOS,
148150
deviceId,

‎lib/common/test/unit-tests/mobile/ios-log-entry.ts‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,47 @@ describe("getIOSLogEntryText", () => {
9898
});
9999
});
100100

101+
describe("getIOSLogEntryText for forwarded stdio", () => {
102+
const entry = {
103+
process: "/var/containers/Bundle/Application/X/app.app/app",
104+
image: "/private/Frameworks/NativeScript.framework/NativeScript",
105+
level: "default",
106+
message: "printed",
107+
subsystem: "org.nativescript.stdio",
108+
category: "stdout",
109+
};
110+
111+
it("is hidden by default, unlike the runtime's console output", () => {
112+
assert.isNull(getIOSLogEntryText(entry, { processName: "app" }));
113+
});
114+
115+
it("is labeled with its stream along with native output", () => {
116+
assert.equal(
117+
getIOSLogEntryText(
118+
{ ...entry, category: "stderr" },
119+
{ processName: "app", includeNative: true },
120+
),
121+
"stderr: printed",
122+
);
123+
});
124+
125+
it("is labeled once when a long line was split", () => {
126+
const stitcher = new IOSLogChunkStitcher();
127+
const printed: string[] = [];
128+
for (const message of ["[ns 4 1/2] one", "[ns 4 2/2] two"]) {
129+
stitcher.add("process", { ...entry, message }, (complete) =>
130+
printed.push(
131+
getIOSLogEntryText(complete, {
132+
processName: "app",
133+
includeNative: true,
134+
}),
135+
),
136+
);
137+
}
138+
assert.deepEqual(printed, ["stdout: one two"]);
139+
});
140+
});
141+
101142
describe("getIOSLogScope", () => {
102143
it("maps the CLI log level to the app logs that are shown", () => {
103144
assert.deepEqual(getIOSLogScope("INFO", false), {

‎lib/controllers/prepare-controller.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ export class PrepareController
527527
}
528528
if (prepareData && !prepareData.release) {
529529
packageData.logFormat = IOS_LOG_FORMAT;
530+
packageData.forwardStdio = true;
530531
}
531532
if (packageData.ios && packageData.ios.discardUncaughtJsExceptions) {
532533
packageData.discardUncaughtJsExceptions =

‎test/controllers/prepare-controller.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,11 @@ describe("prepareController", () => {
178178
return written;
179179
};
180180

181-
it("asks for the structured log format in iOS debug builds only", async () => {
181+
it("asks for the structured log format and stdio in iOS debug builds only", async () => {
182182
assert.equal((await writePackageJson("ios", false)).logFormat, 1);
183183
assert.isUndefined((await writePackageJson("ios", true)).logFormat);
184+
assert.isTrue((await writePackageJson("ios", false)).forwardStdio);
185+
assert.isUndefined((await writePackageJson("ios", true)).forwardStdio);
184186
assert.isUndefined((await writePackageJson("android", false)).logFormat);
185187
});
186188
});

0 commit comments

Comments
 (0)