7
7
#include " nix/util/source-path.hh"
8
8
#include " nix/util/position.hh"
9
9
#include " nix/util/sync.hh"
10
+ #include " nix/util/unix-domain-socket.hh"
10
11
11
12
#include < atomic>
12
13
#include < sstream>
@@ -182,8 +183,12 @@ void to_json(nlohmann::json & json, std::shared_ptr<Pos> pos)
182
183
183
184
struct JSONLogger : Logger {
184
185
Descriptor fd;
186
+ bool includeNixPrefix;
185
187
186
- JSONLogger (Descriptor fd) : fd(fd) { }
188
+ JSONLogger (Descriptor fd, bool includeNixPrefix)
189
+ : fd(fd)
190
+ , includeNixPrefix(includeNixPrefix)
191
+ { }
187
192
188
193
bool isVerbose () override {
189
194
return true ;
@@ -204,20 +209,31 @@ struct JSONLogger : Logger {
204
209
205
210
struct State
206
211
{
212
+ bool enabled = true ;
207
213
};
208
214
209
215
Sync<State> _state;
210
216
211
217
void write (const nlohmann::json & json)
212
218
{
213
219
auto line =
214
- " @nix " +
220
+ (includeNixPrefix ? " @nix " : " " ) +
215
221
json.dump (-1 , ' ' , false , nlohmann::json::error_handler_t ::replace);
216
222
217
223
/* Acquire a lock to prevent log messages from clobbering each
218
224
other. */
219
- auto state (_state.lock ());
220
- writeLine (fd, line);
225
+ try {
226
+ auto state (_state.lock ());
227
+ if (state->enabled )
228
+ writeLine (fd, line);
229
+ } catch (...) {
230
+ bool enabled = false ;
231
+ std::swap (_state.lock ()->enabled , enabled);
232
+ if (enabled) {
233
+ ignoreExceptionExceptInterrupt ();
234
+ logger->warn (" disabling JSON logger due to write errors" );
235
+ }
236
+ }
221
237
}
222
238
223
239
void log (Verbosity lvl, std::string_view s) override
@@ -289,9 +305,49 @@ struct JSONLogger : Logger {
289
305
}
290
306
};
291
307
292
- std::unique_ptr<Logger> makeJSONLogger (Descriptor fd)
308
+ std::unique_ptr<Logger> makeJSONLogger (Descriptor fd, bool includeNixPrefix)
309
+ {
310
+ return std::make_unique<JSONLogger>(fd, includeNixPrefix);
311
+ }
312
+
313
+ std::unique_ptr<Logger> makeJSONLogger (const std::filesystem::path & path, bool includeNixPrefix)
314
+ {
315
+ struct JSONFileLogger : JSONLogger {
316
+ AutoCloseFD fd;
317
+
318
+ JSONFileLogger (AutoCloseFD && fd, bool includeNixPrefix)
319
+ : JSONLogger(fd.get(), includeNixPrefix)
320
+ , fd(std::move(fd))
321
+ { }
322
+ };
323
+
324
+ AutoCloseFD fd =
325
+ std::filesystem::is_socket (path)
326
+ ? connect (path)
327
+ : toDescriptor (open (path.c_str (), O_CREAT | O_APPEND | O_WRONLY, 0644 ));
328
+ if (!fd)
329
+ throw SysError (" opening log file %1%" , path);
330
+
331
+ return std::make_unique<JSONFileLogger>(std::move (fd), includeNixPrefix);
332
+ }
333
+
334
+ void applyJSONLogger ()
293
335
{
294
- return std::make_unique<JSONLogger>(fd);
336
+ if (!loggerSettings.jsonLogPath .get ().empty ()) {
337
+ try {
338
+ std::vector<std::unique_ptr<Logger>> loggers;
339
+ loggers.push_back (makeJSONLogger (std::filesystem::path (loggerSettings.jsonLogPath .get ()), false ));
340
+ try {
341
+ logger = makeTeeLogger (std::move (logger), std::move (loggers));
342
+ } catch (...) {
343
+ // `logger` is now gone so give up.
344
+ abort ();
345
+ }
346
+ } catch (...) {
347
+ ignoreExceptionExceptInterrupt ();
348
+ }
349
+
350
+ }
295
351
}
296
352
297
353
static Logger::Fields getFields (nlohmann::json & json)
0 commit comments