logging-spec.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { app } from 'electron';
  2. import { expect } from 'chai';
  3. import { startRemoteControlApp, ifdescribe } from './lib/spec-helpers';
  4. import * as fs from 'node:fs/promises';
  5. import * as path from 'node:path';
  6. import * as uuid from 'uuid';
  7. import { once } from 'node:events';
  8. function isTestingBindingAvailable () {
  9. try {
  10. process._linkedBinding('electron_common_testing');
  11. return true;
  12. } catch {
  13. return false;
  14. }
  15. }
  16. // This test depends on functions that are only available when DCHECK_IS_ON.
  17. ifdescribe(isTestingBindingAvailable())('logging', () => {
  18. it('does not log by default', async () => {
  19. // ELECTRON_ENABLE_LOGGING is turned on in the appveyor config.
  20. const { ELECTRON_ENABLE_LOGGING: _, ...envWithoutEnableLogging } = process.env;
  21. const rc = await startRemoteControlApp([], { env: envWithoutEnableLogging });
  22. const stderrComplete = new Promise<string>(resolve => {
  23. let stderr = '';
  24. rc.process.stderr!.on('data', function listener (chunk) {
  25. stderr += chunk.toString('utf8');
  26. });
  27. rc.process.on('close', () => { resolve(stderr); });
  28. });
  29. const [hasLoggingSwitch, hasLoggingVar] = await rc.remotely(() => {
  30. // Make sure we're actually capturing stderr by logging a known value to
  31. // stderr.
  32. console.error('SENTINEL');
  33. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  34. setTimeout(() => { process.exit(0); });
  35. return [require('electron').app.commandLine.hasSwitch('enable-logging'), !!process.env.ELECTRON_ENABLE_LOGGING];
  36. });
  37. expect(hasLoggingSwitch).to.be.false();
  38. expect(hasLoggingVar).to.be.false();
  39. const stderr = await stderrComplete;
  40. // stderr should include the sentinel but not the LOG() message.
  41. expect(stderr).to.match(/SENTINEL/);
  42. expect(stderr).not.to.match(/TEST_LOG/);
  43. });
  44. it('logs to stderr when --enable-logging is passed', async () => {
  45. const rc = await startRemoteControlApp(['--enable-logging']);
  46. const stderrComplete = new Promise<string>(resolve => {
  47. let stderr = '';
  48. rc.process.stderr!.on('data', function listener (chunk) {
  49. stderr += chunk.toString('utf8');
  50. });
  51. rc.process.on('close', () => { resolve(stderr); });
  52. });
  53. rc.remotely(() => {
  54. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  55. setTimeout(() => { require('electron').app.quit(); });
  56. });
  57. const stderr = await stderrComplete;
  58. expect(stderr).to.match(/TEST_LOG/);
  59. });
  60. it('logs to stderr when ELECTRON_ENABLE_LOGGING is set', async () => {
  61. const rc = await startRemoteControlApp([], { env: { ...process.env, ELECTRON_ENABLE_LOGGING: '1' } });
  62. const stderrComplete = new Promise<string>(resolve => {
  63. let stderr = '';
  64. rc.process.stderr!.on('data', function listener (chunk) {
  65. stderr += chunk.toString('utf8');
  66. });
  67. rc.process.on('close', () => { resolve(stderr); });
  68. });
  69. rc.remotely(() => {
  70. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  71. setTimeout(() => { require('electron').app.quit(); });
  72. });
  73. const stderr = await stderrComplete;
  74. expect(stderr).to.match(/TEST_LOG/);
  75. });
  76. it('logs to a file in the user data dir when --enable-logging=file is passed', async () => {
  77. const rc = await startRemoteControlApp(['--enable-logging=file']);
  78. const userDataDir = await rc.remotely(() => {
  79. const { app } = require('electron');
  80. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  81. setTimeout(() => { app.quit(); });
  82. return app.getPath('userData');
  83. });
  84. await once(rc.process, 'exit');
  85. const logFilePath = path.join(userDataDir, 'electron_debug.log');
  86. const stat = await fs.stat(logFilePath);
  87. expect(stat.isFile()).to.be.true();
  88. const contents = await fs.readFile(logFilePath, 'utf8');
  89. expect(contents).to.match(/TEST_LOG/);
  90. });
  91. it('logs to a file in the user data dir when ELECTRON_ENABLE_LOGGING=file is set', async () => {
  92. const rc = await startRemoteControlApp([], { env: { ...process.env, ELECTRON_ENABLE_LOGGING: 'file' } });
  93. const userDataDir = await rc.remotely(() => {
  94. const { app } = require('electron');
  95. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  96. setTimeout(() => { app.quit(); });
  97. return app.getPath('userData');
  98. });
  99. await once(rc.process, 'exit');
  100. const logFilePath = path.join(userDataDir, 'electron_debug.log');
  101. const stat = await fs.stat(logFilePath);
  102. expect(stat.isFile()).to.be.true();
  103. const contents = await fs.readFile(logFilePath, 'utf8');
  104. expect(contents).to.match(/TEST_LOG/);
  105. });
  106. it('logs to the given file when --log-file is passed', async () => {
  107. const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4());
  108. const rc = await startRemoteControlApp(['--enable-logging', '--log-file=' + logFilePath]);
  109. rc.remotely(() => {
  110. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  111. setTimeout(() => { require('electron').app.quit(); });
  112. });
  113. await once(rc.process, 'exit');
  114. const stat = await fs.stat(logFilePath);
  115. expect(stat.isFile()).to.be.true();
  116. const contents = await fs.readFile(logFilePath, 'utf8');
  117. expect(contents).to.match(/TEST_LOG/);
  118. });
  119. it('logs to the given file when ELECTRON_LOG_FILE is set', async () => {
  120. const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4());
  121. const rc = await startRemoteControlApp([], { env: { ...process.env, ELECTRON_ENABLE_LOGGING: '1', ELECTRON_LOG_FILE: logFilePath } });
  122. rc.remotely(() => {
  123. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  124. setTimeout(() => { require('electron').app.quit(); });
  125. });
  126. await once(rc.process, 'exit');
  127. const stat = await fs.stat(logFilePath);
  128. expect(stat.isFile()).to.be.true();
  129. const contents = await fs.readFile(logFilePath, 'utf8');
  130. expect(contents).to.match(/TEST_LOG/);
  131. });
  132. it('does not lose early log messages when logging to a given file with --log-file', async () => {
  133. const logFilePath = path.join(app.getPath('temp'), 'test-log-file-' + uuid.v4());
  134. const rc = await startRemoteControlApp(['--enable-logging', '--log-file=' + logFilePath, '--boot-eval=process._linkedBinding(\'electron_common_testing\').log(0, \'EARLY_LOG\')']);
  135. rc.remotely(() => {
  136. process._linkedBinding('electron_common_testing').log(0, 'LATER_LOG');
  137. setTimeout(() => { require('electron').app.quit(); });
  138. });
  139. await once(rc.process, 'exit');
  140. const stat = await fs.stat(logFilePath);
  141. expect(stat.isFile()).to.be.true();
  142. const contents = await fs.readFile(logFilePath, 'utf8');
  143. expect(contents).to.match(/EARLY_LOG/);
  144. expect(contents).to.match(/LATER_LOG/);
  145. });
  146. it('enables logging when switch is appended during first tick', async () => {
  147. const rc = await startRemoteControlApp(['--boot-eval=require(\'electron\').app.commandLine.appendSwitch(\'--enable-logging\')']);
  148. const stderrComplete = new Promise<string>(resolve => {
  149. let stderr = '';
  150. rc.process.stderr!.on('data', function listener (chunk) {
  151. stderr += chunk.toString('utf8');
  152. });
  153. rc.process.on('close', () => { resolve(stderr); });
  154. });
  155. rc.remotely(() => {
  156. process._linkedBinding('electron_common_testing').log(0, 'TEST_LOG');
  157. setTimeout(() => { require('electron').app.quit(); });
  158. });
  159. const stderr = await stderrComplete;
  160. expect(stderr).to.match(/TEST_LOG/);
  161. });
  162. it('respects --log-level', async () => {
  163. const rc = await startRemoteControlApp(['--enable-logging', '--log-level=1']);
  164. const stderrComplete = new Promise<string>(resolve => {
  165. let stderr = '';
  166. rc.process.stderr!.on('data', function listener (chunk) {
  167. stderr += chunk.toString('utf8');
  168. });
  169. rc.process.on('close', () => { resolve(stderr); });
  170. });
  171. rc.remotely(() => {
  172. process._linkedBinding('electron_common_testing').log(0, 'TEST_INFO_LOG');
  173. process._linkedBinding('electron_common_testing').log(1, 'TEST_WARNING_LOG');
  174. setTimeout(() => { require('electron').app.quit(); });
  175. });
  176. const stderr = await stderrComplete;
  177. expect(stderr).to.match(/TEST_WARNING_LOG/);
  178. expect(stderr).not.to.match(/TEST_INFO_LOG/);
  179. });
  180. });