Skip to content

Commit 7285859

Browse files
authored
feat!: Add support for viewing auto-generated keys in Structured IR files. (#192)
1 parent 1e8455e commit 7285859

File tree

9 files changed

+250
-91
lines changed

9 files changed

+250
-91
lines changed

package-lock.json

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"@mui/icons-material": "^6.4.1",
3131
"@mui/joy": "^5.0.0-beta.51",
3232
"axios": "^1.7.9",
33-
"clp-ffi-js": "^0.3.4",
33+
"clp-ffi-js": "^0.4.0",
3434
"dayjs": "^1.11.13",
3535
"monaco-editor": "0.50.0",
3636
"react": "^19.0.0",
@@ -50,11 +50,11 @@
5050
"copy-webpack-plugin": "^12.0.2",
5151
"css-loader": "^7.1.2",
5252
"eslint-config-yscope": "latest",
53-
"html-webpack-plugin": "^5.6.3",
5453
"globals": "^15.14.0",
54+
"html-webpack-plugin": "^5.6.3",
5555
"jest": "^29.7.0",
56-
"mini-css-extract-plugin": "^2.9.2",
5756
"jest-environment-jsdom": "^29.7.0",
57+
"mini-css-extract-plugin": "^2.9.2",
5858
"monaco-editor-webpack-plugin": "^7.1.0",
5959
"npm-run-all": "^4.1.5",
6060
"prettier": "^3.4.2",

src/services/decoders/ClpIrDecoder.ts renamed to src/services/decoders/ClpIrDecoder/index.ts

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,59 @@
1-
import clpFfiJsModuleInit, {ClpStreamReader} from "clp-ffi-js";
1+
import clpFfiJsModuleInit, {
2+
ClpStreamReader,
3+
MainModule,
4+
} from "clp-ffi-js";
25
import {Dayjs} from "dayjs";
36

4-
import {Nullable} from "../../typings/common";
7+
import {Nullable} from "../../../typings/common";
58
import {
69
Decoder,
710
DecodeResult,
811
DecoderOptions,
912
FilteredLogEventMap,
1013
LogEventCount,
11-
} from "../../typings/decoders";
12-
import {Formatter} from "../../typings/formatters";
13-
import {JsonObject} from "../../typings/js";
14-
import {LogLevelFilter} from "../../typings/logs";
15-
import YscopeFormatter from "../formatters/YscopeFormatter";
16-
import {postFormatPopup} from "../MainWorker";
14+
} from "../../../typings/decoders";
15+
import {Formatter} from "../../../typings/formatters";
16+
import {JsonObject} from "../../../typings/js";
17+
import {LogLevelFilter} from "../../../typings/logs";
18+
import YscopeFormatter from "../../formatters/YscopeFormatter";
19+
import {postFormatPopup} from "../../MainWorker";
1720
import {
1821
convertToDayjsTimestamp,
1922
isJsonObject,
20-
} from "./JsonlDecoder/utils";
21-
23+
} from "../JsonlDecoder/utils";
24+
import {
25+
CLP_IR_STREAM_TYPE,
26+
getStructuredIrNamespaceKeys,
27+
StructuredIrNamespaceKeys,
28+
} from "./utils";
2229

23-
enum CLP_IR_STREAM_TYPE {
24-
STRUCTURED = "structured",
25-
UNSTRUCTURED = "unstructured",
26-
}
2730

2831
class ClpIrDecoder implements Decoder {
2932
#streamReader: ClpStreamReader;
3033

3134
readonly #streamType: CLP_IR_STREAM_TYPE;
3235

36+
readonly #structuredIrNamespaceKeys: StructuredIrNamespaceKeys;
37+
3338
#formatter: Nullable<Formatter> = null;
3439

3540
constructor (
36-
streamType: CLP_IR_STREAM_TYPE,
37-
streamReader: ClpStreamReader,
41+
ffiModule: MainModule,
42+
dataArray: Uint8Array,
3843
decoderOptions: DecoderOptions
3944
) {
40-
this.#streamType = streamType;
41-
this.#streamReader = streamReader;
42-
if (streamType === CLP_IR_STREAM_TYPE.STRUCTURED) {
43-
this.#formatter = new YscopeFormatter({formatString: decoderOptions.formatString});
45+
this.#streamReader = new ffiModule.ClpStreamReader(dataArray, decoderOptions);
46+
this.#streamType =
47+
this.#streamReader.getIrStreamType() === ffiModule.IrStreamType.STRUCTURED ?
48+
CLP_IR_STREAM_TYPE.STRUCTURED :
49+
CLP_IR_STREAM_TYPE.UNSTRUCTURED;
50+
this.#structuredIrNamespaceKeys = getStructuredIrNamespaceKeys(ffiModule);
51+
52+
if (this.#streamType === CLP_IR_STREAM_TYPE.STRUCTURED) {
53+
this.#formatter = new YscopeFormatter({
54+
formatString: decoderOptions.formatString,
55+
structuredIrNamespaceKeys: this.#structuredIrNamespaceKeys,
56+
});
4457
if (0 === decoderOptions.formatString.length) {
4558
postFormatPopup();
4659
}
@@ -61,12 +74,7 @@ class ClpIrDecoder implements Decoder {
6174
decoderOptions: DecoderOptions
6275
): Promise<ClpIrDecoder> {
6376
const module = await clpFfiJsModuleInit();
64-
const streamReader = new module.ClpStreamReader(dataArray, decoderOptions);
65-
const streamType = streamReader.getIrStreamType() === module.IrStreamType.STRUCTURED ?
66-
CLP_IR_STREAM_TYPE.STRUCTURED :
67-
CLP_IR_STREAM_TYPE.UNSTRUCTURED;
68-
69-
return new ClpIrDecoder(streamType, streamReader, decoderOptions);
77+
return new ClpIrDecoder(module, dataArray, decoderOptions);
7078
}
7179

7280
getEstimatedNumEvents (): number {
@@ -91,7 +99,10 @@ class ClpIrDecoder implements Decoder {
9199
}
92100

93101
setFormatterOptions (options: DecoderOptions): boolean {
94-
this.#formatter = new YscopeFormatter({formatString: options.formatString});
102+
this.#formatter = new YscopeFormatter({
103+
formatString: options.formatString,
104+
structuredIrNamespaceKeys: this.#structuredIrNamespaceKeys,
105+
});
95106

96107
return true;
97108
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {MainModule} from "clp-ffi-js";
2+
3+
4+
enum CLP_IR_STREAM_TYPE {
5+
STRUCTURED = "structured",
6+
UNSTRUCTURED = "unstructured",
7+
}
8+
9+
/**
10+
* Keys that delineate the auto-generated and user-generated namespaces in structured IR log events.
11+
*/
12+
interface StructuredIrNamespaceKeys {
13+
autoGenerated: string;
14+
userGenerated: string;
15+
}
16+
17+
/**
18+
* Retrieves the structured IR namespace keys from the "clp-ffi-js" module.
19+
*
20+
* @param ffiModule The main module from "clp-ffi-js".
21+
* @return
22+
* @throws {Error} If the keys are of invalid type.
23+
*/
24+
const getStructuredIrNamespaceKeys = (ffiModule: MainModule): StructuredIrNamespaceKeys => {
25+
const {MERGED_KV_PAIRS_AUTO_GENERATED_KEY, MERGED_KV_PAIRS_USER_GENERATED_KEY} = ffiModule;
26+
27+
if ("string" !== typeof MERGED_KV_PAIRS_AUTO_GENERATED_KEY) {
28+
throw new Error("Invalid type for MERGED_KV_PAIRS_AUTO_GENERATED_KEY.");
29+
}
30+
31+
if ("string" !== typeof MERGED_KV_PAIRS_USER_GENERATED_KEY) {
32+
throw new Error("Invalid type for MERGED_KV_PAIRS_USER_GENERATED_KEY.");
33+
}
34+
35+
return {
36+
autoGenerated: MERGED_KV_PAIRS_AUTO_GENERATED_KEY,
37+
userGenerated: MERGED_KV_PAIRS_USER_GENERATED_KEY,
38+
};
39+
};
40+
41+
42+
export type {StructuredIrNamespaceKeys};
43+
export {
44+
CLP_IR_STREAM_TYPE,
45+
getStructuredIrNamespaceKeys,
46+
};

src/services/formatters/YscopeFormatter/FieldFormatters/RoundFormatter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Nullable} from "../../../../typings/common";
22
import {YscopeFieldFormatter} from "../../../../typings/formatters";
33
import {JsonValue} from "../../../../typings/js";
4-
import {jsonValueToString} from "../utils";
4+
import {jsonValueToString} from "../../../../utils/js";
55

66

77
/**

src/services/formatters/YscopeFormatter/index.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import {
88
YscopeFieldPlaceholder,
99
} from "../../../typings/formatters";
1010
import {LogEvent} from "../../../typings/logs";
11+
import {jsonValueToString} from "../../../utils/js";
12+
import {StructuredIrNamespaceKeys} from "../../decoders/ClpIrDecoder/utils";
1113
import {
1214
getFormattedField,
13-
jsonValueToString,
1415
removeEscapeCharacters,
1516
replaceDoubleBacklash,
1617
splitFieldPlaceholder,
@@ -25,12 +26,16 @@ import {
2526
class YscopeFormatter implements Formatter {
2627
readonly #processedFormatString: string;
2728

29+
readonly #structuredIrNamespaceKeys: Nullable<StructuredIrNamespaceKeys>;
30+
2831
#fieldPlaceholders: YscopeFieldPlaceholder[] = [];
2932

3033
constructor (options: FormatterOptionsType) {
34+
this.#structuredIrNamespaceKeys = options.structuredIrNamespaceKeys ?? null;
35+
3136
if (options.formatString.includes(REPLACEMENT_CHARACTER)) {
32-
console.warn("Unicode replacement character `U+FFFD` is found in Decoder Format" +
33-
' String, which will appear as "\\".');
37+
console.warn("Unicode replacement character `U+FFFD` found in format string; " +
38+
"it will be replaced with \"\\\"");
3439
}
3540

3641
this.#processedFormatString = replaceDoubleBacklash(options.formatString);
@@ -51,7 +56,11 @@ class YscopeFormatter implements Formatter {
5156
this.#processedFormatString.slice(lastIndex, fieldPlaceholder.range.start);
5257

5358
formattedLogFragments.push(removeEscapeCharacters(formatStringFragment));
54-
formattedLogFragments.push(getFormattedField(logEvent, fieldPlaceholder));
59+
formattedLogFragments.push(getFormattedField(
60+
this.#structuredIrNamespaceKeys,
61+
logEvent,
62+
fieldPlaceholder
63+
));
5564
lastIndex = fieldPlaceholder.range.end;
5665
}
5766

@@ -62,9 +71,9 @@ class YscopeFormatter implements Formatter {
6271
}
6372

6473
/**
65-
* Parses field placeholders in format string. For each field placeholder, creates a
66-
* corresponding `YscopeFieldFormatter` using the placeholder's field name, formatter type,
67-
* and formatter options. Each `YscopeFieldFormatter` is then stored on the
74+
* Parses field placeholders in format string. For each field, creates a corresponding
75+
* `YscopeFieldPlaceholder` using the placeholder's parsed field name, formatter type,
76+
* and formatter options. Each `YscopeFieldPlaceholder` is then stored on the
6877
* class-level array `#fieldPlaceholders`.
6978
*
7079
* @throws Error if `FIELD_PLACEHOLDER_REGEX` does not contain a capture group.
@@ -81,8 +90,8 @@ class YscopeFormatter implements Formatter {
8190
throw Error("Field placeholder regex is invalid and does not have a capture group");
8291
}
8392

84-
const {fieldNameKeys, formatterName, formatterOptions} =
85-
splitFieldPlaceholder(groupMatch);
93+
const {parsedFieldName, formatterName, formatterOptions} =
94+
splitFieldPlaceholder(groupMatch, this.#structuredIrNamespaceKeys);
8695

8796
let fieldFormatter: Nullable<YscopeFieldFormatter> = null;
8897
if (null !== formatterName) {
@@ -94,7 +103,7 @@ class YscopeFormatter implements Formatter {
94103
}
95104

96105
this.#fieldPlaceholders.push({
97-
fieldNameKeys: fieldNameKeys,
106+
parsedFieldName: parsedFieldName,
98107
fieldFormatter: fieldFormatter,
99108
range: {
100109
start: match.index,

0 commit comments

Comments
 (0)