File size: 2,277 Bytes
68d7816
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { LifecycleScope } from '#/app/scopes';

import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
import { defineState } from '#/state/state';
import { ISessionContext } from '#/session/sessionContext/sessionContext';
import { ISessionStateService } from '#/session/state/sessionState';

import { ILogService, type LogLevel } from '#/_base/log/log';
import { createFileLogWriter, type FileLogWriter } from '#/_base/log/fileLog';
import { ILogOptions, resolveSessionLogPath } from '#/_base/log/logConfig';
import { BoundLogger, trackLogClose, type LogLevelState } from '#/_base/log/logService';

export const sessionLogRootLevelKey = defineState<LogLevelState>('sessionLog.rootLevel', () => ({
  level: 'info',
}));

function seedRootLevel(states: ISessionStateService, level: LogLevel): LogLevelState {
  states.contributeState(sessionLogRootLevelKey);
  states.set(sessionLogRootLevelKey, { level });
  return states.get(sessionLogRootLevelKey);
}

export class SessionLogService extends BoundLogger implements ILogService {
  declare readonly _serviceBrand: undefined;
  private readonly sink: FileLogWriter;

  constructor(
    @ISessionStateService private readonly states: ISessionStateService,
    @ILogOptions options: ILogOptions,
    @ISessionContext session: ISessionContext,
  ) {
    const sink = createFileLogWriter({
      path: resolveSessionLogPath(session.sessionDir),
      maxBytes: options.sessionMaxBytes,
      files: options.sessionFiles,
      format: { omitContextKeys: ['sessionId'] },
    });
    super(sink, seedRootLevel(states, options.level), { sessionId: session.sessionId });
    this.sink = sink;
  }

  private get rootLevel(): LogLevelState {
    return this.states.get(sessionLogRootLevelKey);
  }

  get level(): LogLevel {
    return this.rootLevel.level;
  }

  setLevel(level: LogLevel): void {
    this.rootLevel.level = level;
  }

  flush(): Promise<void> {
    return this.sink.flush();
  }

  close(): Promise<void> {
    return this.sink.close();
  }

  override dispose(): void {
    this.sink.flushSync();
    trackLogClose(this.sink.close());
    super.dispose();
  }
}

registerScopedService(
  LifecycleScope.Session,
  ILogService,
  SessionLogService,
  ScopeActivation.OnScopeCreated,
  'log',
);