1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-26 09:33:22 +00:00

feat: include callee information

This commit is contained in:
Andreas Coroiu
2025-12-08 13:30:59 +01:00
parent 2c617b1090
commit 081eb1047b
9 changed files with 202 additions and 33 deletions

View File

@@ -1641,6 +1641,7 @@ const safeProviders: SafeProvider[] = [
ApiServiceAbstraction,
StateProvider,
ConfigService,
LogService,
],
}),
safeProvider({

View File

@@ -20,6 +20,7 @@ import { UserId } from "../../../types/guid";
import { UserKey } from "../../../types/key";
import { ConfigService } from "../../abstractions/config/config.service";
import { Environment, EnvironmentService } from "../../abstractions/environment.service";
import { LogService } from "../../abstractions/log.service";
import { PlatformUtilsService } from "../../abstractions/platform-utils.service";
import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory";
import { SdkLoadService } from "../../abstractions/sdk/sdk-load.service";
@@ -49,6 +50,7 @@ describe("DefaultSdkService", () => {
let service!: DefaultSdkService;
let accountService!: FakeAccountService;
let fakeStateProvider!: FakeStateProvider;
let logService!: MockProxy<LogService>;
let apiService!: MockProxy<ApiService>;
beforeEach(async () => {
@@ -64,6 +66,7 @@ describe("DefaultSdkService", () => {
const mockUserId = Utils.newGuid() as UserId;
accountService = mockAccountServiceWith(mockUserId);
fakeStateProvider = new FakeStateProvider(accountService);
logService = mock<LogService>();
configService = mock<ConfigService>();
configService.serverConfig$ = new BehaviorSubject(null);
@@ -82,6 +85,7 @@ describe("DefaultSdkService", () => {
apiService,
fakeStateProvider,
configService,
logService,
);
});

View File

@@ -23,11 +23,8 @@ import { KeyService, KdfConfigService, KdfConfig, KdfType } from "@bitwarden/key
import {
PasswordManagerClient,
ClientSettings,
EventDefinition,
FieldValue,
DeviceType as SdkDeviceType,
Span,
SpanDefinition,
TokenProvider,
TracingLevel,
UnsignedSharedKey,
@@ -40,6 +37,7 @@ import { EncString } from "../../../key-management/crypto/models/enc-string";
import { SecurityStateService } from "../../../key-management/security-state/abstractions/security-state.service";
import { OrganizationId, UserId } from "../../../types/guid";
import { Environment, EnvironmentService } from "../../abstractions/environment.service";
import { LogService } from "../../abstractions/log.service";
import { PlatformUtilsService } from "../../abstractions/platform-utils.service";
import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory";
import { SdkLoadService } from "../../abstractions/sdk/sdk-load.service";
@@ -55,34 +53,34 @@ import { StateProvider } from "../../state";
import { initializeState } from "./client-managed-state";
const UserClientSpan = SdkLoadService.WithSdk(
() =>
new SpanDefinition("userClient$", "DefaultSdkService", TracingLevel.Info, [
"userId",
"hasOverride",
]),
);
// const UserClientSpan = SdkLoadService.WithSdk(
// () =>
// new SpanDefinition("userClient$", "DefaultSdkService", TracingLevel.Info, [
// "userId",
// "hasOverride",
// ]),
// );
const InitializeClientSpan = SdkLoadService.WithSdk(
// TODO: We can remove userId because it's already in the parent span
() => new SpanDefinition("initializeClient", "DefaultSdkService", TracingLevel.Info, ["userId"]),
);
// const InitializeClientSpan = SdkLoadService.WithSdk(
// // TODO: We can remove userId because it's already in the parent span
// () => new SpanDefinition("initializeClient", "DefaultSdkService", TracingLevel.Info, ["userId"]),
// );
const UserCryptoInitializedEvent = SdkLoadService.WithSdk(
() => new EventDefinition("User crypto initialized", "DefaultSdkService", TracingLevel.Info, []),
);
// const UserCryptoInitializedEvent = SdkLoadService.WithSdk(
// () => new EventDefinition("User crypto initialized", "DefaultSdkService", TracingLevel.Info, []),
// );
const OrgCryptoInitializedEvent = SdkLoadService.WithSdk(
() => new EventDefinition("Org crypto initialized", "DefaultSdkService", TracingLevel.Info, []),
);
// const OrgCryptoInitializedEvent = SdkLoadService.WithSdk(
// () => new EventDefinition("Org crypto initialized", "DefaultSdkService", TracingLevel.Info, []),
// );
const ClientStateInitializedEvent = SdkLoadService.WithSdk(
() => new EventDefinition("Client state initialized", "DefaultSdkService", TracingLevel.Info, []),
);
// const ClientStateInitializedEvent = SdkLoadService.WithSdk(
// () => new EventDefinition("Client state initialized", "DefaultSdkService", TracingLevel.Info, []),
// );
const FeatureFlagsLoadedEvent = SdkLoadService.WithSdk(
() => new EventDefinition("Feature flags loaded", "DefaultSdkService", TracingLevel.Info, []),
);
// const FeatureFlagsLoadedEvent = SdkLoadService.WithSdk(
// () => new EventDefinition("Feature flags loaded", "DefaultSdkService", TracingLevel.Info, []),
// );
// A symbol that represents an overridden client that is explicitly set to undefined,
// blocking the creation of an internal client for that user.
@@ -142,11 +140,14 @@ export class DefaultSdkService implements SdkService {
private apiService: ApiService,
private stateProvider: StateProvider,
private configService: ConfigService,
private logService: LogService,
private userAgent: string | null = null,
) {}
userClient$(userId: UserId): Observable<Rc<PasswordManagerClient>> {
const span = UserClientSpan.requiredValue.enter([new FieldValue("userId", userId)]);
const span = this.logService.span("userClient$", TracingLevel.Info, [
new FieldValue("userId", userId),
]);
return this.sdkClientOverrides.pipe(
takeWhile((clients) => clients[userId] !== UnsetClient, false),
map((clients) => {
@@ -320,7 +321,10 @@ export class DefaultSdkService implements SdkService {
orgKeys: Record<OrganizationId, EncString>,
parent: Span,
) {
using span = (await InitializeClientSpan).enter_with_parent(parent, [
// using span = (await InitializeClientSpan).enter_with_parent(parent, [
// new FieldValue("userId", userId),
// ]);
using span = this.logService.span("initializeClient", TracingLevel.Info, [
new FieldValue("userId", userId),
]);
@@ -340,7 +344,14 @@ export class DefaultSdkService implements SdkService {
},
accountCryptographicState: accountCryptographicState,
});
span.event(await UserCryptoInitializedEvent, `User crypto initialized for user`);
// span.event(await UserCryptoInitializedEvent, `User crypto initialized for user`);
this.logService.event(
span,
"cryptoInitialized",
`User crypto initialized for user`,
TracingLevel.Info,
[],
);
// We initialize the org crypto even if the org_keys are
// null to make sure any existing org keys are cleared.
@@ -349,14 +360,32 @@ export class DefaultSdkService implements SdkService {
Object.entries(orgKeys).map(([k, v]) => [asUuid(k), v.toJSON() as UnsignedSharedKey]),
),
});
span.event(await OrgCryptoInitializedEvent, `Org crypto initialized for user`);
this.logService.event(
span,
"orgCryptoInitialized",
`Org crypto initialized for user`,
TracingLevel.Info,
[],
);
// Initialize the SDK managed database and the client managed repositories.
await initializeState(userId, client.platform().state(), this.stateProvider);
span.event(await ClientStateInitializedEvent, "Client state initialized");
this.logService.event(
span,
"clientStateInitialized",
`Client state initialized`,
TracingLevel.Info,
[],
);
await this.loadFeatureFlags(client);
span.event(await FeatureFlagsLoadedEvent, "Feature flags loaded");
this.logService.event(
span,
"featureFlagsLoaded",
`Feature flags loaded`,
TracingLevel.Info,
[],
);
}
private async loadFeatureFlags(client: PasswordManagerClient) {

View File

@@ -1,14 +1,81 @@
// import { parse } from "stacktrace-parser";
import StackTrace from "stacktrace-js";
import {
EventDefinition,
FieldValue,
Span,
SpanDefinition,
TracingLevel,
} from "@bitwarden/sdk-internal";
import { LogLevel } from "./log-level";
import { LogService } from "./log.service";
export class ConsoleLogService implements LogService {
protected timersMap: Map<string, [number, number]> = new Map();
protected spanDefinitions = new Map<string, SpanDefinition>();
protected eventDefinitions = new Map<string, EventDefinition>();
constructor(
protected isDev: boolean,
protected filter: ((level: LogLevel) => boolean) | null = null,
) {}
/**
* Creates a new span.
* @param name Name of the span to create. Must be unique in the application.
* // TODO: Consider creating the name as we do state KeyDefinitions.
*/
span(name: string, level: TracingLevel, fields: FieldValue[]): Span {
let definition = this.spanDefinitions.get(name);
if (!definition) {
// TODO: A better way to get the caller info would be to use Webpack to modify
// the code calling logService.span(...) at compile time to inject the file, line, and function name.
const stack = StackTrace.getSync();
const callee = stack[1];
definition = new SpanDefinition(
name,
"",
level,
fields.map((f) => f.name),
callee.fileName,
callee.lineNumber,
callee.functionName,
);
this.spanDefinitions.set(name, definition);
}
return definition.enter(fields);
}
event(
span: Span,
name: string,
message: string,
level: TracingLevel,
fields: FieldValue[],
): void {
let definition = this.eventDefinitions.get(name);
if (!definition) {
// TODO: A better way to get the caller info would be to use Webpack to modify
// the code calling logService.event(...) at compile time to inject the file, line, and function name.
const stack = StackTrace.getSync();
const callee = stack[1];
definition = new EventDefinition(
name,
callee.functionName ?? "",
level,
fields.map((f) => f.name),
callee.fileName,
callee.lineNumber,
callee.functionName,
);
this.eventDefinitions.set(name, definition);
}
span.event(definition, message);
}
debug(message?: any, ...optionalParams: any[]) {
if (!this.isDev) {
return;

View File

@@ -1,6 +1,16 @@
import type { FieldValue, Span, TracingLevel } from "@bitwarden/sdk-internal";
import { LogLevel } from "./log-level";
export abstract class LogService {
abstract span(name: string, level: TracingLevel, fields: FieldValue[]): Span;
abstract event(
span: Span,
name: string,
message: string,
level: TracingLevel,
fields: FieldValue[],
): void;
abstract debug(message?: any, ...optionalParams: any[]): void;
abstract info(message?: any, ...optionalParams: any[]): void;
abstract warning(message?: any, ...optionalParams: any[]): void;