detox 20.0.4-breaking.new-global-lifecycle.0 → 20.0.5-breaking.new-global-lifecycle.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-javadoc.jar} +0 -0
  2. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-javadoc.jar.md5 +1 -0
  3. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +1 -0
  4. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +1 -0
  5. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +1 -0
  6. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-sources.jar} +0 -0
  7. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-sources.jar.md5 +1 -0
  8. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-sources.jar.sha1 +1 -0
  9. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-sources.jar.sha256 +1 -0
  10. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0-sources.jar.sha512 +1 -0
  11. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.aar} +0 -0
  12. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.md5 → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.aar.md5} +0 -0
  13. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha1 → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.aar.sha1} +0 -0
  14. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha256 → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.aar.sha256} +0 -0
  15. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.aar.sha512 → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.aar.sha512} +0 -0
  16. package/Detox-android/com/wix/detox/{20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom → 20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.pom} +1 -1
  17. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.pom.md5 +1 -0
  18. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.pom.sha1 +1 -0
  19. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.pom.sha256 +1 -0
  20. package/Detox-android/com/wix/detox/20.0.5-breaking.new-global-lifecycle.0/detox-20.0.5-breaking.new-global-lifecycle.0.pom.sha512 +1 -0
  21. package/Detox-android/com/wix/detox/maven-metadata.xml +4 -4
  22. package/Detox-android/com/wix/detox/maven-metadata.xml.md5 +1 -1
  23. package/Detox-android/com/wix/detox/maven-metadata.xml.sha1 +1 -1
  24. package/Detox-android/com/wix/detox/maven-metadata.xml.sha256 +1 -1
  25. package/Detox-android/com/wix/detox/maven-metadata.xml.sha512 +1 -1
  26. package/Detox-ios-src.tbz +0 -0
  27. package/Detox-ios.tbz +0 -0
  28. package/index.d.ts +49 -40
  29. package/internals.d.ts +63 -15
  30. package/local-cli/cli.js +1 -1
  31. package/local-cli/rebuild-framework-cache.js +1 -1
  32. package/local-cli/test.js +3 -2
  33. package/local-cli/test.test.js +1 -1
  34. package/local-cli/testCommand/TestRunnerCommand.js +4 -3
  35. package/package.json +5 -4
  36. package/runners/jest/globalSetup.js +1 -1
  37. package/runners/jest/globalTeardown.js +1 -1
  38. package/runners/jest/testEnvironment/index.js +33 -16
  39. package/runners/jest/testEnvironment/listeners/DetoxCoreListener.js +76 -41
  40. package/runners/jest/testEnvironment/listeners/SpecReporter.js +1 -1
  41. package/runners/jest/testEnvironment/listeners/WorkerAssignReporter.js +1 -1
  42. package/src/DetoxWorker.js +4 -1
  43. package/src/artifacts/ArtifactsManager.js +8 -23
  44. package/src/artifacts/instruments/ios/SimulatorInstrumentsRecording.js +3 -3
  45. package/src/artifacts/log/ios/SimulatorLogRecording.js +1 -1
  46. package/src/artifacts/screenshot/SimulatorScreenshotPlugin.js +1 -1
  47. package/src/artifacts/templates/artifact/Artifact.js +1 -1
  48. package/src/artifacts/templates/plugin/ArtifactPlugin.js +1 -1
  49. package/src/artifacts/utils/temporaryPath.js +18 -7
  50. package/src/artifacts/video/SimulatorRecordVideoPlugin.js +1 -1
  51. package/src/client/AsyncWebSocket.js +8 -17
  52. package/src/client/Client.js +1 -1
  53. package/src/configuration/collectCliConfig.js +1 -1
  54. package/src/configuration/composeDeviceConfig.js +1 -1
  55. package/src/configuration/composeLoggerConfig.js +17 -8
  56. package/src/configuration/composeRunnerConfig.js +1 -1
  57. package/src/configuration/index.js +5 -1
  58. package/src/configuration/loadExternalConfig.js +1 -1
  59. package/src/devices/allocation/DeviceAllocator.js +3 -2
  60. package/src/devices/allocation/drivers/android/emulator/AVDValidator.js +1 -1
  61. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocDriver.js +3 -2
  62. package/src/devices/allocation/drivers/android/emulator/EmulatorAllocationHelper.js +1 -1
  63. package/src/devices/allocation/drivers/android/emulator/EmulatorLauncher.js +3 -2
  64. package/src/devices/allocation/drivers/android/emulator/EmulatorVersionResolver.js +4 -6
  65. package/src/devices/allocation/drivers/android/emulator/launchEmulatorProcess.js +1 -1
  66. package/src/devices/allocation/drivers/android/genycloud/GenyInstanceAllocationHelper.js +1 -1
  67. package/src/devices/common/drivers/android/genycloud/services/GenyInstanceNaming.js +3 -3
  68. package/src/devices/common/drivers/android/genycloud/services/GenyRecipesService.js +1 -1
  69. package/src/devices/common/drivers/android/tools/EmulatorTelnet.js +1 -1
  70. package/src/devices/common/drivers/android/tools/FreeDeviceFinder.js +1 -1
  71. package/src/devices/common/drivers/ios/tools/AppleSimUtils.js +1 -1
  72. package/src/devices/lifecycle/GenyGlobalLifecycleHandler.js +9 -13
  73. package/src/devices/runtime/RuntimeDevice.js +7 -8
  74. package/src/devices/runtime/drivers/DeviceDriverBase.js +1 -1
  75. package/src/devices/runtime/drivers/android/AndroidDriver.js +1 -1
  76. package/src/devices/runtime/drivers/ios/SimulatorDriver.js +1 -1
  77. package/src/ipc/IPCClient.js +3 -8
  78. package/src/ipc/IPCServer.js +11 -11
  79. package/src/ipc/{state.js → SessionState.js} +23 -50
  80. package/src/logger/DetoxLogger.js +264 -155
  81. package/src/logger/index.js +4 -0
  82. package/src/logger/utils/BunyanLogger.js +72 -0
  83. package/src/logger/utils/CategoryThreadDispatcher.js +58 -0
  84. package/src/logger/utils/MessageStack.js +24 -0
  85. package/src/logger/{TraceThreadDispatcher.js → utils/ThreadDispatcher.js} +34 -5
  86. package/src/logger/{customConsoleLogger.js → utils/customConsoleLogger.js} +4 -4
  87. package/src/logger/utils/sanitizeBunyanContext.js +28 -0
  88. package/src/logger/utils/tracerLegacy.js +25 -0
  89. package/src/realms/DetoxContext.js +65 -57
  90. package/src/realms/DetoxInternalsFacade.js +7 -5
  91. package/src/realms/DetoxPrimaryContext.js +111 -39
  92. package/src/realms/DetoxSecondaryContext.js +24 -29
  93. package/src/server/DetoxConnection.js +18 -23
  94. package/src/server/DetoxServer.js +7 -10
  95. package/src/server/DetoxSession.js +6 -6
  96. package/src/server/DetoxSessionManager.js +1 -1
  97. package/src/server/handlers/RegisteredConnectionHandler.js +1 -2
  98. package/src/symbols.js +12 -8
  99. package/src/utils/childProcess/exec.js +1 -1
  100. package/src/utils/childProcess/spawn.js +1 -1
  101. package/src/utils/streamUtils.js +10 -11
  102. package/src/utils/trace.js +2 -18
  103. package/src/utils/traceMethods.js +15 -0
  104. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.md5 +0 -1
  105. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha1 +0 -1
  106. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha256 +0 -1
  107. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-javadoc.jar.sha512 +0 -1
  108. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.md5 +0 -1
  109. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha1 +0 -1
  110. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha256 +0 -1
  111. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0-sources.jar.sha512 +0 -1
  112. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.md5 +0 -1
  113. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha1 +0 -1
  114. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha256 +0 -1
  115. package/Detox-android/com/wix/detox/20.0.4-breaking.new-global-lifecycle.0/detox-20.0.4-breaking.new-global-lifecycle.0.pom.sha512 +0 -1
  116. package/src/logger/DetoxTraceEventBuilder.js +0 -21
  117. package/src/logger/DetoxTracer.js +0 -133
  118. package/src/utils/ChromeTracingExporter.js +0 -54
@@ -1,201 +1,335 @@
1
1
  const path = require('path');
2
- const { PassThrough } = require('stream');
3
2
 
4
- const bunyan = require('bunyan');
5
- const bunyanDebugStream = require('bunyan-debug-stream');
6
3
  const _ = require('lodash');
7
4
 
8
5
  const temporaryPath = require('../artifacts/utils/temporaryPath');
9
- const { DetoxInternalError } = require('../errors');
6
+ const { DetoxInternalError, DetoxError } = require('../errors');
10
7
  const { shortFormat } = require('../utils/dateUtils');
8
+ const isPromise = require('../utils/isPromise');
11
9
 
12
- const customConsoleLogger = require('./customConsoleLogger');
10
+ const BunyanLogger = require('./utils/BunyanLogger');
11
+ const CategoryThreadDispatcher = require('./utils/CategoryThreadDispatcher');
12
+ const MessageStack = require('./utils/MessageStack');
13
+ const customConsoleLogger = require('./utils/customConsoleLogger');
14
+ const sanitizeBunyanContext = require('./utils/sanitizeBunyanContext');
13
15
 
14
16
  /**
15
- * @typedef PrivateLoggerConfig
16
- * @property {string} [file]
17
+ * @typedef SharedLoggerConfig
18
+ * @property {string} file
19
+ * @property {Detox.DetoxLoggerConfig} userConfig
20
+ * @property {CategoryThreadDispatcher} [dispatcher]
21
+ * @property {BunyanLogger} [bunyan]
22
+ * @property {MessageStack} [messageStack]
17
23
  */
18
24
 
19
25
  class DetoxLogger {
20
26
  /**
21
- * @param {Detox.DetoxLoggerConfig & PrivateLoggerConfig} [config]
27
+ * @param {Pick<SharedLoggerConfig, 'file' | 'userConfig'>} sharedConfig
22
28
  * @param {object} [context]
23
- * @param {bunyan} [bunyanLogger]
24
29
  */
25
- constructor(config, context, bunyanLogger) {
26
- // IMPORTANT: all the loggers should share the same object instance of this._config
27
- this._config = config || {
28
- level: 'info',
29
- overrideConsole: 'none',
30
- options: {
31
- showDate: true,
32
- showLoggerName: true,
33
- showPid: true,
34
- showMetadata: false,
35
- },
36
- };
37
-
38
- if (config && !context) {
39
- this._config.file = temporaryPath.for.jsonl();
30
+ constructor(sharedConfig, context) {
31
+ /**
32
+ * @type {SharedLoggerConfig}
33
+ * IMPORTANT: all instances of {@link DetoxLogger} must share the same object instance of this._sharedConfig.
34
+ */
35
+ this._sharedConfig = sharedConfig;
36
+
37
+ if (!context) {
38
+ // In this branch, `this` refers to the first (root) logger instance.
39
+
40
+ this._sharedConfig.userConfig = this._sharedConfig.userConfig || {
41
+ level: 'info',
42
+ overrideConsole: 'none',
43
+ options: {
44
+ showDate: true,
45
+ showLoggerName: true,
46
+ showPid: true,
47
+ showPrefixes: false,
48
+ showMetadata: false,
49
+ },
50
+ };
51
+
52
+ this._sharedConfig.bunyan = new BunyanLogger()
53
+ .installFileStream(this.file)
54
+ .installDebugStream(this.config);
55
+
56
+ this._sharedConfig.dispatcher = new CategoryThreadDispatcher({
57
+ logger: this,
58
+ categories: {
59
+ 'lifecycle': [0],
60
+ 'cli': [1],
61
+ 'logger': [2],
62
+ 'ipc': [29],
63
+ 'ws-server': [50, 99],
64
+ 'ws-client': [100, 149],
65
+ 'device': [150, 159],
66
+ 'artifacts-manager': [300],
67
+ 'artifacts-plugin': [310, 349],
68
+ 'artifact': [350, 399],
69
+ 'child-process': [400, 499],
70
+ 'default': [999],
71
+ 'user': [10000, 10999]
72
+ },
73
+ });
74
+
75
+ this._sharedConfig.messageStack = new MessageStack();
76
+
77
+ this.overrideConsole();
40
78
  }
41
79
 
42
80
  /** @type {object | undefined} */
43
81
  this._context = context;
44
- /** @type {bunyan} */
45
- this._bunyan = bunyanLogger || this._initBunyanLogger();
46
82
 
47
- this.fatal = this._forward.bind(this, 'fatal');
48
- this.error = this._forward.bind(this, 'error');
49
- this.warn = this._forward.bind(this, 'warn');
50
- this.info = this._forward.bind(this, 'info');
51
- this.debug = this._forward.bind(this, 'debug');
52
- this.trace = this._forward.bind(this, 'trace');
53
-
54
- this.overrideConsole();
83
+ /** @public */
84
+ this.fatal = this._setupLogMethod('fatal');
85
+ /** @public */
86
+ this.error = this._setupLogMethod('error');
87
+ /** @public */
88
+ this.warn = this._setupLogMethod('warn');
89
+ /** @public */
90
+ this.info = this._setupLogMethod('info');
91
+ /** @public */
92
+ this.debug = this._setupLogMethod('debug');
93
+ /** @public */
94
+ this.trace = this._setupLogMethod('trace');
55
95
  }
56
96
 
57
97
  /**
58
- * @internal
98
+ * @public
99
+ * @returns {Detox.DetoxLogLevel}
59
100
  */
60
- get config() {
61
- return this._config;
62
- }
63
-
64
- /** @returns {Detox.DetoxLogLevel} */
65
101
  get level() {
66
- return this._config.level;
102
+ return this.config.level;
67
103
  }
68
104
 
69
105
  /**
70
- * @internal
106
+ * @public
107
+ * @param {object} [overrides]
108
+ * @returns {DetoxLogger}
71
109
  */
110
+ child(overrides) {
111
+ const merged = this._mergeContexts(this._context, overrides);
112
+ return new DetoxLogger(this._sharedConfig, merged);
113
+ }
114
+
115
+ /** @internal */
116
+ get config() {
117
+ return this._sharedConfig.userConfig;
118
+ }
119
+
120
+ /** @internal */
72
121
  get file() {
73
- return this._config.file;
122
+ return this._sharedConfig.file;
74
123
  }
75
124
 
76
125
  /**
126
+ * @internal
77
127
  * @param config
78
128
  */
79
129
  async setConfig(config) {
80
- if (this._context !== undefined) {
81
- throw new DetoxInternalError('Trying to set a config for a non-root logger');
130
+ if (this._context) {
131
+ throw new DetoxInternalError('Trying to set a config in a non-root logger');
82
132
  }
83
133
 
84
- if (this.file) {
85
- throw new DetoxInternalError('Trying to set a config for a fully initialized logger');
86
- }
87
-
88
- _.merge(this._config, config);
89
-
90
- // @ts-ignore
91
- const [oldStream] = this._bunyan.streams.splice(0, 1);
92
- oldStream.stream.end();
93
- this._bunyan.addStream(this._createDebugStream());
134
+ _.merge(this.config, config);
135
+ this._sharedConfig.file = temporaryPath.for.jsonl();
136
+ this._sharedConfig.bunyan.installDebugStream(this.config);
137
+ this.overrideConsole();
138
+ }
94
139
 
95
- this._config.file = temporaryPath.for.jsonl();
96
- this._bunyan.addStream({
97
- level: 'trace',
98
- path: this._config.file,
99
- });
140
+ /**
141
+ * @internal
142
+ */
143
+ overrideConsole(sandbox) {
144
+ const option = this.config.overrideConsole;
145
+ if (option === 'none') {
146
+ return;
147
+ }
100
148
 
101
- this.overrideConsole();
149
+ if ((option === 'sandbox' && sandbox) || option === 'all') {
150
+ customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
151
+ }
102
152
  }
103
153
 
104
154
  /**
105
- * @param {object} [overrides]
106
- * @returns {DetoxLogger}
155
+ * @private
107
156
  */
108
- child(overrides) {
109
- if (overrides && overrides.__filename) {
110
- overrides.__filename = path.basename(overrides.__filename, '.js');
157
+ _mergeContexts(...contexts) {
158
+ const context = Object.assign({}, ...contexts);
159
+
160
+ if (context.error || context.err) {
161
+ context.error = DetoxError.format(context.error || context.err);
162
+ delete context.err;
163
+ }
164
+
165
+ if (Array.isArray(context.cat)) {
166
+ context.cat = context.cat.join(',');
167
+ }
168
+
169
+ if (context.__filename) {
170
+ context.__filename = path.basename(context.__filename);
111
171
  }
112
172
 
113
- return new DetoxLogger(this._config, {
114
- ...this._context,
115
- ...overrides,
116
- }, this._bunyan);
173
+ context.ph = context.ph || 'i';
174
+ context.cat = context.cat || '';
175
+
176
+ context.tid = this._sharedConfig.dispatcher.resolve(
177
+ context.ph,
178
+ context.cat,
179
+ context.id || 0
180
+ );
181
+
182
+ return sanitizeBunyanContext(context);
117
183
  }
118
184
 
119
185
  /**
120
- * @param {bunyan.LogLevel} level
121
- * @param {any[]} args
122
186
  * @private
187
+ * @param {Detox.DetoxLogLevel} level
188
+ * @returns {Detox._LogMethod}
123
189
  */
124
- _forward(level, ...args) {
125
- const msgContext = _.isError(args[0]) ? { err: args[0] } : _.isObject(args[0]) ? args[0] : undefined;
126
- const msgArgs = msgContext !== undefined ? args.slice(1) : args;
127
- const mergedContext = sanitizeBunyanContext({
128
- ...this._context,
129
- ...msgContext,
130
- });
190
+ _setupLogMethod(level) {
191
+ const logMethod = this[level] = this._instant.bind(this, level);
131
192
 
132
- this._bunyan[level](mergedContext, ...msgArgs);
193
+ return Object.assign(logMethod, {
194
+ begin: this._begin.bind(this, level),
195
+ complete: this._complete.bind(this, level),
196
+ end: this._end.bind(this, level),
197
+ });
133
198
  }
134
199
 
135
- _initBunyanLogger() {
136
- /** @type {bunyan.Stream[]} */
137
- const streams = [this._createDebugStream()];
200
+ /** @private */
201
+ _begin(level, ...args) {
202
+ const { context, msg } = this._parseArgs({ ph: 'B' }, args);
203
+ this._sharedConfig.messageStack.push(context.tid, msg);
204
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
205
+ }
138
206
 
139
- if (this._config.file) {
140
- streams.push({
141
- level: 'trace',
142
- path: this._config.file,
143
- });
207
+ /** @private */
208
+ _end(level, ...args) {
209
+ let { context, msg } = this._parseArgs({ ph: 'E' }, args);
210
+ if (msg.length === 0) {
211
+ msg = this._sharedConfig.messageStack.pop(context.tid);
144
212
  }
145
213
 
146
- return bunyan.createLogger({ name: 'detox', streams });
214
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
147
215
  }
148
216
 
149
- _createDebugStream() {
150
- const { out = process.stderr, ...streamOptions } = this._config.options;
151
- const passthrough = new PassThrough().pipe(out);
152
-
153
- return {
154
- type: 'raw',
155
- level: this._config.level,
156
- stream: bunyanDebugStream.default({
157
- ...streamOptions,
158
- out: passthrough,
159
- }),
160
- };
217
+ /**
218
+ * @private
219
+ * @param {import('bunyan').LogLevel} level
220
+ * @param {any[]} args
221
+ */
222
+ _instant(level, ...args) {
223
+ const { context, msg } = this._parseArgs(null, args);
224
+ this._sharedConfig.bunyan.logger[level](context, ...msg);
161
225
  }
162
226
 
163
- overrideConsole(sandbox) {
164
- const option = this._config.overrideConsole;
165
- if (option === 'none') {
166
- return;
227
+ /**
228
+ * @param {import('bunyan').LogLevel} level
229
+ * @private
230
+ */
231
+ _complete(level, maybeContext, maybeMessage, maybeAction) {
232
+ const action = typeof maybeContext !== 'string' ? maybeAction : maybeMessage;
233
+ const args = maybeAction === action ? [maybeContext, maybeMessage] : [maybeContext];
234
+ const { context, msg } = this._parseArgs(null, args);
235
+ const end = (ctx) => this[level].end(ctx);
236
+
237
+ let result;
238
+ this[level].begin(context, ...msg);
239
+ try {
240
+ result = typeof action === 'function'
241
+ ? action()
242
+ : action;
243
+
244
+ if (!isPromise(result)) {
245
+ end(context);
246
+ } else {
247
+ result.then(
248
+ () => end({ success: true }),
249
+ (err) => end({ success: false, err }),
250
+ );
251
+ }
252
+
253
+ return result;
254
+ } catch (err) {
255
+ end({ success: false, err });
256
+ throw err;
167
257
  }
258
+ }
168
259
 
169
- if ((option === 'sandbox' && sandbox) || option === 'all') {
170
- customConsoleLogger.overrideConsoleMethods((sandbox || global).console, this);
260
+ /** @private */
261
+ _parseArgs(boundContext, args) {
262
+ const userContext = _.isError(args[0])
263
+ ? { err: args[0] }
264
+ : _.isObject(args[0])
265
+ ? args[0]
266
+ : undefined;
267
+ const msg = userContext !== undefined ? args.slice(1) : args;
268
+
269
+ if (userContext) {
270
+ delete userContext.pid;
271
+ delete userContext.tid;
272
+ delete userContext.ts;
273
+ delete userContext.time;
274
+ delete userContext.ph;
171
275
  }
276
+
277
+ const context = this._mergeContexts(
278
+ this._context,
279
+ boundContext,
280
+ userContext,
281
+ );
282
+
283
+ return { context, msg };
172
284
  }
173
285
 
174
- /** @type {bunyanDebugStream.BunyanDebugStreamOptions} */
175
- static defaultOptions = {
176
- showDate: shortFormat,
177
- showLoggerName: true,
178
- showPid: true,
179
- showMetadata: false,
180
- basepath: path.join(__dirname, '..'),
181
- prefixers: {
182
- '__filename': (filename, { entry }) => {
183
- if (entry.event === 'USER_LOG') {
184
- return '';
185
- }
186
-
187
- if (entry.event === 'ERROR') {
188
- return `${filename}/${entry.event}`;
189
- }
190
-
191
- return entry.event ? entry.event : filename;
192
- },
193
- 'trackingId': id => ` #${id}`,
194
- 'cpid': pid => ` cpid=${pid}`,
195
- },
196
- };
286
+ /** @internal */
287
+ static defaultOptions({ level }) {
288
+ const ph = level === 'trace' || level === 'debug'
289
+ ? value => require('chalk').grey(value) + ' '
290
+ : value => require('chalk').grey(value);
291
+
292
+ const id = level === 'trace'
293
+ ? value => require('chalk').yellow(`@${value}`)
294
+ : undefined;
295
+
296
+ const cat = level === 'trace' || level === 'debug'
297
+ ? (value) => require('chalk').yellow((value || '').split(',', 1)[0])
298
+ : undefined;
299
+
300
+ const event = level === 'trace' || level === 'debug'
301
+ ? (value) => require('chalk').grey(`:${value}`)
302
+ : undefined;
303
+
304
+ const identity = x => x;
305
+
306
+ return ({
307
+ showDate: shortFormat,
308
+ showLoggerName: true,
309
+ showPid: true,
310
+ showLevel: false,
311
+ showMetadata: false,
312
+ showPrefixes: (p) => p.join(''),
313
+ basepath: path.join(__dirname, '..'),
314
+ prefixers: _.omitBy({
315
+ ph,
316
+ cat,
317
+ event,
318
+ id,
319
+ }, _.isUndefined),
320
+ stringifiers: _.omitBy({
321
+ // eslint-disable-next-line unicorn/no-array-method-this-argument
322
+ 'args': args => `(${require('lodash').map(args, a => JSON.stringify(a)).join(', ')})`,
323
+ 'error': identity,
324
+ 'data': json => typeof json === 'string' ? json : JSON.stringify(json, null, 2),
325
+ 'stack': level === 'trace' || level === 'debug' ? identity : undefined,
326
+ 'origin': level === 'trace' || level === 'debug' ? identity : undefined,
327
+ }, _.isUndefined),
328
+ });
329
+ }
197
330
 
198
331
  /**
332
+ * @internal
199
333
  * @param {string} level
200
334
  * @returns {Detox.DetoxLogLevel}
201
335
  */
@@ -216,29 +350,4 @@ class DetoxLogger {
216
350
  }
217
351
  }
218
352
 
219
- const RESERVED_PROPERTIES = [
220
- 'hostname',
221
- 'level',
222
- 'msg',
223
- 'name',
224
- 'pid',
225
- 'time',
226
- ];
227
-
228
- function hasProperty(p) {
229
- return _.has(this, p);
230
- }
231
-
232
- function hasReservedProperties(o) {
233
- return RESERVED_PROPERTIES.some(hasProperty, o); // eslint-disable-line unicorn/no-array-method-this-argument
234
- }
235
-
236
- function escapeCallback(value, key) {
237
- return RESERVED_PROPERTIES.includes(key) ? `${key}$` : key;
238
- }
239
-
240
- function sanitizeBunyanContext(context) {
241
- return hasReservedProperties(context) ? _.mapKeys(context, escapeCallback) : context;
242
- }
243
-
244
353
  module.exports = DetoxLogger;
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ DetoxLogger: require('./DetoxLogger'),
3
+ installLegacyTracerInterface: require('./utils/tracerLegacy').install,
4
+ };
@@ -0,0 +1,72 @@
1
+ const { PassThrough } = require('stream');
2
+
3
+ const bunyan = require('bunyan');
4
+ const bds = require('bunyan-debug-stream');
5
+ const _ = require('lodash');
6
+
7
+ const { DetoxInternalError } = require('../../errors');
8
+
9
+ class BunyanLogger {
10
+ constructor() {
11
+ this._bunyan = bunyan.createLogger({ name: 'detox', streams: [] });
12
+ /** @type {bunyan.Stream} */
13
+ this._debugStream = null;
14
+ /** @type {bunyan.Stream} */
15
+ this._fileStream = null;
16
+ }
17
+
18
+ /**
19
+ * @returns {bunyan}
20
+ */
21
+ get logger() {
22
+ return this._bunyan;
23
+ }
24
+
25
+ /**
26
+ * @param {Detox.DetoxLoggerConfig} config
27
+ * @returns {this}
28
+ */
29
+ installDebugStream(config) {
30
+ const level = config.level || 'info';
31
+
32
+ if (this._debugStream) {
33
+ _.remove(this._bunyan['streams'], this._debugStream);
34
+ // @ts-ignore
35
+ this._debugStream.stream.end();
36
+ this._debugStream = null;
37
+ }
38
+
39
+ this._debugStream = {
40
+ type: 'raw',
41
+ level,
42
+ stream: bds.default({
43
+ ...config.options,
44
+ out: new PassThrough().pipe(process.stderr),
45
+ }),
46
+ };
47
+
48
+ this._bunyan.addStream(this._debugStream);
49
+ return this;
50
+ }
51
+
52
+ /**
53
+ * @param {string} file
54
+ * @returns {this}
55
+ */
56
+ installFileStream(file) {
57
+ if (this._fileStream) {
58
+ throw new DetoxInternalError('Trying to install a second file stream inside already initialized Bunyan logger');
59
+ }
60
+
61
+ this._fileStream = {
62
+ level: 'trace',
63
+ path: file,
64
+ };
65
+
66
+ this._bunyan.addStream(this._fileStream);
67
+
68
+ return this;
69
+ }
70
+ }
71
+
72
+ module.exports = BunyanLogger;
@@ -0,0 +1,58 @@
1
+ const _ = require('lodash');
2
+
3
+ const ThreadDispatcher = require('./ThreadDispatcher');
4
+
5
+ class CategoryThreadDispatcher {
6
+ /**
7
+ * @param {object} config
8
+ * @param {Record<string, [number, number?]>} config.categories
9
+ * @param {Detox.Logger} config.logger
10
+ */
11
+ constructor(config) {
12
+ this.categories = config.categories;
13
+ this.dispatchers = _.mapValues(this.categories, (range, name) => {
14
+ return new ThreadDispatcher({
15
+ name,
16
+ logger: config.logger,
17
+ min: range[0],
18
+ max: range[1] || range[0],
19
+ });
20
+ });
21
+ }
22
+
23
+ /**
24
+ * @param {'B' | 'E' | 'i'} ph
25
+ * @param {string[] | undefined} cat
26
+ * @param {string | number} id
27
+ * @returns {number}
28
+ */
29
+ resolve(ph, cat, id) {
30
+ const dispatcher = this._resolveDispatcher(cat);
31
+
32
+ switch (ph) {
33
+ case 'B': return dispatcher.begin(id);
34
+ case 'E': return dispatcher.end(id);
35
+ default: return dispatcher.resolve(id);
36
+ }
37
+ }
38
+
39
+ /** @returns {ThreadDispatcher} */
40
+ _resolveDispatcher(cat) {
41
+ const mainCategory = cat ? cat.split(',', 1)[0] : '';
42
+ return this.dispatchers[mainCategory] || this.dispatchers.default;
43
+ }
44
+
45
+ categorize(tid) {
46
+ return _.findKey(this.categories, ([min, max]) => min <= tid && tid <= max) || 'default';
47
+ }
48
+
49
+ threadize(cat) {
50
+ if (!cat) {
51
+ return this.categories.default[0];
52
+ }
53
+
54
+ return _.find(this.categories, (_, key) => key === cat[0]);
55
+ }
56
+ }
57
+
58
+ module.exports = CategoryThreadDispatcher;
@@ -0,0 +1,24 @@
1
+ class MessageStack {
2
+ constructor() {
3
+ this._map = {};
4
+ }
5
+
6
+ push(tid, msg) {
7
+ if (this._map[tid] == null) {
8
+ this._map[tid] = [];
9
+ }
10
+
11
+ return this._map[tid].push(msg);
12
+ }
13
+
14
+ pop(tid) {
15
+ const stack = this._map[tid];
16
+ if (stack == null || stack.length === 0) {
17
+ return ['<no begin message>'];
18
+ }
19
+
20
+ return stack.pop();
21
+ }
22
+ }
23
+
24
+ module.exports = MessageStack;