Is it thread-safe to use the same LoggerHandle in scheduled Jobs and their systems?

To be Burst compatible Unity provides logging via Unity.Logging namespace (package: com.unity.logging). In my setup I create a LoggerHandle for every struct implementing ISystem. Each logger handle writes into a separate file with a custom formatter using its own scope like this:

    public static Unity.Logging.LoggerHandle CreateLogger(string name)
    {
      var logger = new Unity.Logging.LoggerConfig()
        .MinimumLevel.Debug()
        .WriteTo.File(@$"C:\temp\MyGameLogs\{name}.clef",
          formatter: LogFormatterClef.Formatter, maxFileSizeBytes: 1024 * 1024 * 100)
        #if UNITY_EDITOR
        .WriteTo.UnityEditorConsole()
        #endif
        .CreateLogger();

      // The scope lasts forever
      Unity.Logging.Log.To(logger.Handle).Decorate("SourceContext", name);
     
      return logger.Handle;
    }

The logger handle will be created in the OnCreate() of the system and supplied to jobs like this:

using Unity.Logging;
// ...
[BurstCompile]
public partial struct ServerConnectionSystem : ISystem
{
  /// <inheritdoc />
  public void OnCreate(ref SystemState state)
  {
    this._logger = LogFactory.CreateLogger(nameof(ServerConnectionSystem));
    // ...
  }
 
  [BurstCompile]
  public void OnUpdate(ref SystemState state)
  {
    if (!this._initializeConnectionQuery.IsEmpty)
    {
      Log.To(this._logger).Info("[{SystemTime:00000}] New connection incoming", SystemAPI.Time.ElapsedTime);
     
      var initializeConnectionJob = new InitializeConnectionJob()
      {
        CommandBuffer = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>().CreateCommandBuffer(state.WorldUnmanaged),
        JobLogger = this._logger,
      };
   
      initializeConnectionJob.Schedule(this._initializeConnectionQuery);
    }
  }

  [BurstCompile]
  private partial struct InitializeConnectionJob : IJobEntity
  {     
    public EntityCommandBuffer CommandBuffer;
    public LoggerHandle JobLogger;

    [BurstCompile]
    public void Execute(Entity connectionEntity, in NetworkId networkId)
    {
      Log.To(this.JobLogger).Info("Client with network ID {NetworkId} is connected", networkId.Value);
      this.CommandBuffer.AddComponent<InitializedConnection>(connectionEntity);
      this.CommandBuffer.AddComponent<ConnectionState>(connectionEntity);
    }
  }
}

It currently works this way. But you know, it may work a thousand times and then one-time log entries gone missing cause of race conditions. So is it thread-safe to use the same LoggerHandle of systems also in scheduled jobs? Didn’t find anything on the sparse Logging documentation.

I would that it is safe as long that you know that none of the scheduled jobs will be able to run in parallel with each other (so always make a new scheduled job depend on the previous one).

Yep, that would be safe, because the logger handle is only used by one thread at a time.

I made some multithreading tests using 4 bursted jobs/threads using the same logger handler, writing to the same file. Then a small amount of log entries did NOT find their way into the log file. So it is NOT thread-safe and the only safety is to use separate logger handles for each parallel job writing in a separate log file.