@hpcc-js/comms 3.15.4 → 3.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -43
- package/README.md +50 -50
- package/dist/browser/index.js +1 -1
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.umd.cjs +1 -1
- package/dist/browser/index.umd.cjs.map +1 -1
- package/dist/node/index.cjs +10 -10
- package/dist/node/index.cjs.map +4 -4
- package/dist/node/index.js +9 -9
- package/dist/node/index.js.map +4 -4
- package/package.json +7 -7
- package/src/__package__.ts +3 -3
- package/src/clienttools/eclMeta.ts +506 -506
- package/src/clienttools/eclcc.ts +628 -628
- package/src/connection.ts +288 -288
- package/src/ecl/activity.ts +82 -82
- package/src/ecl/dfuWorkunit.ts +363 -363
- package/src/ecl/graph.ts +196 -196
- package/src/ecl/logicalFile.ts +196 -196
- package/src/ecl/machine.ts +63 -63
- package/src/ecl/query.ts +265 -265
- package/src/ecl/queryGraph.ts +813 -813
- package/src/ecl/resource.ts +39 -39
- package/src/ecl/result.ts +245 -245
- package/src/ecl/scope.ts +188 -188
- package/src/ecl/sourceFile.ts +34 -34
- package/src/ecl/store.ts +154 -154
- package/src/ecl/targetCluster.ts +149 -149
- package/src/ecl/timer.ts +42 -42
- package/src/ecl/topology.ts +131 -131
- package/src/ecl/workunit.ts +1340 -1340
- package/src/ecl/xsdParser.ts +267 -267
- package/src/espConnection.ts +164 -164
- package/src/index.browser.ts +1 -1
- package/src/index.common.ts +40 -40
- package/src/index.node.ts +48 -48
- package/src/pem/trustwave.ts +909 -909
- package/src/services/fileSpray.ts +73 -73
- package/src/services/wsAccess.ts +8 -8
- package/src/services/wsAccount.ts +27 -27
- package/src/services/wsCloud.ts +73 -73
- package/src/services/wsCodesign.ts +18 -18
- package/src/services/wsDFU.ts +34 -34
- package/src/services/wsDFUXRef.ts +121 -121
- package/src/services/wsDali.ts +8 -8
- package/src/services/wsEcl.ts +123 -123
- package/src/services/wsElk.ts +8 -8
- package/src/services/wsLogaccess.ts +270 -270
- package/src/services/wsMachine.ts +89 -89
- package/src/services/wsPackageProcess.ts +8 -8
- package/src/services/wsResources.ts +8 -8
- package/src/services/wsSMC.ts +80 -80
- package/src/services/wsSasha.ts +7 -7
- package/src/services/wsStore.ts +32 -32
- package/src/services/wsTopology.ts +45 -45
- package/src/services/wsWorkunits.ts +151 -151
- package/src/services/wsdl/FileSpray/v1.23/FileSpray.ts +1008 -1008
- package/src/services/wsdl/FileSpray/v1.25/FileSpray.ts +1040 -1040
- package/src/services/wsdl/FileSpray/v1.26/FileSpray.ts +929 -929
- package/src/services/wsdl/FileSpray/v1.27/FileSpray.ts +930 -930
- package/src/services/wsdl/WsCloud/v1/WsCloud.ts +38 -38
- package/src/services/wsdl/WsCloud/v1.02/WsCloud.ts +77 -77
- package/src/services/wsdl/WsDFUXRef/v1.02/WsDFUXRef.ts +224 -224
- package/src/services/wsdl/WsDFUXRef/v1.04/WsDFUXRef.ts +228 -227
- package/src/services/wsdl/WsDali/v1.04/WsDali.ts +216 -216
- package/src/services/wsdl/WsDali/v1.07/WsDali.ts +72 -72
- package/src/services/wsdl/WsDfu/v1.62/WsDfu.ts +1455 -1455
- package/src/services/wsdl/WsDfu/v1.63/WsDfu.ts +1465 -1465
- package/src/services/wsdl/WsDfu/v1.65/WsDfu.ts +1244 -1244
- package/src/services/wsdl/WsDfu/v1.66/WsDfu.ts +1267 -1267
- package/src/services/wsdl/WsDfu/v1.67/WsDfu.ts +1268 -1268
- package/src/services/wsdl/WsDfu/v1.68/WsDfu.ts +1301 -0
- package/src/services/wsdl/WsESDLConfig/v1.5/WsESDLConfig.ts +366 -0
- package/src/services/wsdl/WsFileIO/v1.01/WsFileIO.ts +104 -104
- package/src/services/wsdl/WsPackageProcess/v1.04/WsPackageProcess.ts +519 -519
- package/src/services/wsdl/WsPackageProcess/v1.07/WsPackageProcess.ts +500 -500
- package/src/services/wsdl/WsPackageProcess/v1.08/WsPackageProcess.ts +503 -0
- package/src/services/wsdl/WsResources/v1.01/WsResources.ts +119 -119
- package/src/services/wsdl/WsSMC/v1.24/WsSMC.ts +665 -665
- package/src/services/wsdl/WsSMC/v1.27/WsSMC.ts +591 -591
- package/src/services/wsdl/WsSMC/v1.28/WsSMC.ts +645 -645
- package/src/services/wsdl/WsSMC/v1.29/WsSMC.ts +660 -660
- package/src/services/wsdl/WsSasha/v1.01/WsSasha.ts +18 -18
- package/src/services/wsdl/WsTopology/v1.31/WsTopology.ts +856 -856
- package/src/services/wsdl/WsTopology/v1.32/WsTopology.ts +786 -786
- package/src/services/wsdl/WsTopology/v1.33/WsTopology.ts +835 -835
- package/src/services/wsdl/WsWorkunits/v1.88/WsWorkunits.ts +2944 -2944
- package/src/services/wsdl/WsWorkunits/v1.94/WsWorkunits.ts +3072 -3072
- package/src/services/wsdl/WsWorkunits/v1.95/WsWorkunits.ts +3073 -3073
- package/src/services/wsdl/WsWorkunits/v1.97/WsWorkunits.ts +3134 -3134
- package/src/services/wsdl/WsWorkunits/v1.98/WsWorkunits.ts +3182 -3182
- package/src/services/wsdl/WsWorkunits/v1.99/WsWorkunits.ts +3162 -3162
- package/src/services/wsdl/WsWorkunits/v2/WsWorkunits.ts +3153 -3153
- package/src/services/wsdl/WsWorkunits/v2.02/WsWorkunits.ts +3162 -3162
- package/src/services/wsdl/WsWorkunits/v2.03/WsWorkunits.ts +3164 -3164
- package/src/services/wsdl/WsWorkunits/v2.04/WsWorkunits.ts +3171 -3171
- package/src/services/wsdl/WsWorkunits/v2.05/WsWorkunits.ts +3177 -0
- package/src/services/wsdl/ws_access/v1.16/ws_access.ts +1086 -1086
- package/src/services/wsdl/ws_access/v1.17/ws_access.ts +1023 -1023
- package/src/services/wsdl/ws_account/v1.05/ws_account.ts +111 -111
- package/src/services/wsdl/ws_account/v1.06/ws_account.ts +109 -109
- package/src/services/wsdl/ws_account/v1.07/ws_account.ts +114 -114
- package/src/services/wsdl/ws_codesign/v1.1/ws_codesign.ts +95 -95
- package/src/services/wsdl/ws_elk/v1/ws_elk.ts +47 -47
- package/src/services/wsdl/ws_logaccess/v1/ws_logaccess.ts +83 -83
- package/src/services/wsdl/ws_logaccess/v1.02/ws_logaccess.ts +161 -161
- package/src/services/wsdl/ws_logaccess/v1.03/ws_logaccess.ts +190 -190
- package/src/services/wsdl/ws_logaccess/v1.04/ws_logaccess.ts +215 -215
- package/src/services/wsdl/ws_logaccess/v1.05/ws_logaccess.ts +219 -219
- package/src/services/wsdl/ws_logaccess/v1.08/ws_logaccess.ts +267 -267
- package/src/services/wsdl/ws_machine/v1.17/ws_machine.ts +567 -567
- package/src/services/wsdl/ws_machine/v1.18/ws_machine.ts +497 -497
- package/src/services/wsdl/ws_machine/v1.19/ws_machine.ts +497 -497
- package/src/services/wsdl/wsstore/v1.02/wsstore.ts +239 -239
- package/types/services/wsPackageProcess.d.ts +1 -1
- package/types/services/wsWorkunits.d.ts +1 -1
- package/types/services/wsdl/FileSpray/v1.27/FileSpray.d.ts +506 -506
- package/types/services/wsdl/WsCloud/v1.02/WsCloud.d.ts +18 -18
- package/types/services/wsdl/WsDFUXRef/v1.04/WsDFUXRef.d.ts +58 -57
- package/types/services/wsdl/WsDali/v1.07/WsDali.d.ts +42 -42
- package/types/services/wsdl/WsPackageProcess/{v1.07 → v1.08}/WsPackageProcess.d.ts +121 -118
- package/types/services/wsdl/WsSasha/v1.01/WsSasha.d.ts +13 -13
- package/types/services/wsdl/WsTopology/v1.33/WsTopology.d.ts +360 -360
- package/types/services/wsdl/WsWorkunits/v2.05/WsWorkunits.d.ts +2571 -0
- package/types/services/wsdl/ws_access/v1.17/ws_access.d.ts +268 -268
- package/types/services/wsdl/ws_account/v1.07/ws_account.d.ts +34 -34
- package/types/services/wsdl/ws_codesign/v1.1/ws_codesign.d.ts +22 -22
- package/types/services/wsdl/ws_elk/v1/ws_elk.d.ts +12 -12
- package/types/services/wsdl/wsstore/v1.02/wsstore.d.ts +61 -61
- package/types/services/wsdl/WsWorkunits/v2.04/WsWorkunits.d.ts +0 -2565
|
@@ -1,270 +1,270 @@
|
|
|
1
|
-
import { scopedLogger } from "@hpcc-js/util";
|
|
2
|
-
import { LogaccessServiceBase, WsLogaccess } from "./wsdl/ws_logaccess/v1.08/ws_logaccess.ts";
|
|
3
|
-
|
|
4
|
-
const logger = scopedLogger("@hpcc-js/comms/services/wsLogaccess.ts");
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
WsLogaccess
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export interface GetLogsExRequest {
|
|
11
|
-
audience?: string;
|
|
12
|
-
class?: string[];
|
|
13
|
-
workunits?: string;
|
|
14
|
-
message?: string;
|
|
15
|
-
processid?: string;
|
|
16
|
-
logid?: string;
|
|
17
|
-
threadid?: string;
|
|
18
|
-
timestamp?: string;
|
|
19
|
-
components?: string;
|
|
20
|
-
instance?: string;
|
|
21
|
-
StartDate?: Date;
|
|
22
|
-
EndDate?: Date;
|
|
23
|
-
LogLineStartFrom: number,
|
|
24
|
-
LogLineLimit: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const enum LogType {
|
|
28
|
-
Disaster = "DIS",
|
|
29
|
-
Error = "ERR",
|
|
30
|
-
Warning = "WRN",
|
|
31
|
-
Information = "INF",
|
|
32
|
-
Progress = "PRO",
|
|
33
|
-
Metric = "MET"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const enum TargetAudience {
|
|
37
|
-
Operator = "OPR",
|
|
38
|
-
User = "USR",
|
|
39
|
-
Programmer = "PRO",
|
|
40
|
-
Audit = "ADT"
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// properties here are "LogType" values in Ws_logaccess.GetLogAccessInfo
|
|
44
|
-
export interface LogLine {
|
|
45
|
-
audience?: string;
|
|
46
|
-
class?: string;
|
|
47
|
-
workunits?: string;
|
|
48
|
-
message?: string;
|
|
49
|
-
processid?: number;
|
|
50
|
-
logid?: string;
|
|
51
|
-
threadid?: number;
|
|
52
|
-
timestamp?: string;
|
|
53
|
-
components?: string;
|
|
54
|
-
instance?: string;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface GetLogsExResponse {
|
|
58
|
-
lines: LogLine[],
|
|
59
|
-
total: number,
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const knownLogManagerTypes = new Set(["azureloganalyticscurl", "elasticstack", "grafanacurl"]);
|
|
63
|
-
const logColumnTypeValues = new Set(Object.values(WsLogaccess.LogColumnType));
|
|
64
|
-
|
|
65
|
-
function getLogCategory(searchField: string): WsLogaccess.LogAccessType {
|
|
66
|
-
switch (searchField) {
|
|
67
|
-
case WsLogaccess.LogColumnType.workunits:
|
|
68
|
-
case "hpcc.log.jobid":
|
|
69
|
-
return WsLogaccess.LogAccessType.ByJobID;
|
|
70
|
-
case WsLogaccess.LogColumnType.audience:
|
|
71
|
-
case "hpcc.log.audience":
|
|
72
|
-
return WsLogaccess.LogAccessType.ByTargetAudience;
|
|
73
|
-
case WsLogaccess.LogColumnType.class:
|
|
74
|
-
case "hpcc.log.class":
|
|
75
|
-
return WsLogaccess.LogAccessType.ByLogType;
|
|
76
|
-
case WsLogaccess.LogColumnType.components:
|
|
77
|
-
case "kubernetes.container.name":
|
|
78
|
-
return WsLogaccess.LogAccessType.ByComponent;
|
|
79
|
-
default:
|
|
80
|
-
return WsLogaccess.LogAccessType.ByFieldName;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Explicit list of filter-bearing keys on GetLogsExRequest.
|
|
85
|
-
// Using an allowlist avoids accidentally treating control fields (StartDate, LogLineLimit, etc.)
|
|
86
|
-
// as log filters if the server ever returns a column whose name collides with them.
|
|
87
|
-
const FILTER_KEYS = ["audience", "class", "workunits", "message", "processid", "logid", "threadid", "timestamp", "components", "instance"] as const;
|
|
88
|
-
|
|
89
|
-
function buildFilters(request: GetLogsExRequest, columnMap: Record<string, string>): WsLogaccess.leftFilter[] {
|
|
90
|
-
const filters: WsLogaccess.leftFilter[] = [];
|
|
91
|
-
for (const key of FILTER_KEYS) {
|
|
92
|
-
const value = request[key];
|
|
93
|
-
if (value == null || value === "" || (Array.isArray(value) && value.length === 0)) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (!(key in columnMap)) continue;
|
|
97
|
-
|
|
98
|
-
const isKnownLogType = logColumnTypeValues.has(key as WsLogaccess.LogColumnType);
|
|
99
|
-
let searchField: string = isKnownLogType ? key : columnMap[key];
|
|
100
|
-
const logCategory = getLogCategory(searchField);
|
|
101
|
-
if (logCategory === WsLogaccess.LogAccessType.ByFieldName) {
|
|
102
|
-
searchField = columnMap[key];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const appendWildcard = logCategory === WsLogaccess.LogAccessType.ByComponent;
|
|
106
|
-
const rawValues: string[] = Array.isArray(value) ? value : [value as string];
|
|
107
|
-
for (const raw of rawValues) {
|
|
108
|
-
filters.push({
|
|
109
|
-
LogCategory: logCategory,
|
|
110
|
-
SearchField: searchField,
|
|
111
|
-
// append wildcard to end of search value to include ephemeral
|
|
112
|
-
// containers that aren't listed in ECL Watch's filters
|
|
113
|
-
SearchByValue: appendWildcard ? raw + "*" : raw
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return filters;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Builds a left-leaning OR chain from filters that share the same SearchField.
|
|
121
|
-
function buildOrGroup(group: WsLogaccess.leftFilter[]): WsLogaccess.BinaryLogFilter {
|
|
122
|
-
const root: WsLogaccess.BinaryLogFilter = { leftFilter: group[0] } as WsLogaccess.BinaryLogFilter;
|
|
123
|
-
let node = root;
|
|
124
|
-
for (let i = 1; i < group.length; i++) {
|
|
125
|
-
node.Operator = WsLogaccess.LogAccessFilterOperator.OR;
|
|
126
|
-
if (i === group.length - 1) {
|
|
127
|
-
node.rightFilter = group[i] as WsLogaccess.rightFilter;
|
|
128
|
-
} else {
|
|
129
|
-
node.rightBinaryFilter = { BinaryLogFilter: [{ leftFilter: group[i] } as WsLogaccess.BinaryLogFilter] };
|
|
130
|
-
node = node.rightBinaryFilter.BinaryLogFilter[0];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return root;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Recursively AND-chains two or more groups into a BinaryLogFilter (used for nesting beyond depth 1).
|
|
137
|
-
function buildAndChain(groups: WsLogaccess.leftFilter[][]): WsLogaccess.BinaryLogFilter {
|
|
138
|
-
const [firstGroup, ...remainingGroups] = groups;
|
|
139
|
-
const node: WsLogaccess.BinaryLogFilter = {} as WsLogaccess.BinaryLogFilter;
|
|
140
|
-
if (firstGroup.length === 1) {
|
|
141
|
-
node.leftFilter = firstGroup[0];
|
|
142
|
-
} else {
|
|
143
|
-
node.leftBinaryFilter = { BinaryLogFilter: [buildOrGroup(firstGroup)] };
|
|
144
|
-
}
|
|
145
|
-
if (remainingGroups.length === 0) return node;
|
|
146
|
-
node.Operator = WsLogaccess.LogAccessFilterOperator.AND;
|
|
147
|
-
if (remainingGroups.length === 1) {
|
|
148
|
-
const [secondGroup] = remainingGroups;
|
|
149
|
-
if (secondGroup.length === 1) {
|
|
150
|
-
node.rightFilter = secondGroup[0] as WsLogaccess.rightFilter;
|
|
151
|
-
} else {
|
|
152
|
-
node.rightBinaryFilter = { BinaryLogFilter: [buildOrGroup(secondGroup)] };
|
|
153
|
-
}
|
|
154
|
-
} else {
|
|
155
|
-
node.rightBinaryFilter = { BinaryLogFilter: [buildAndChain(remainingGroups)] };
|
|
156
|
-
}
|
|
157
|
-
return node;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Groups filters by SearchField, OR-chains each group, then AND-chains the groups together.
|
|
161
|
-
// This ensures e.g. [class_INF, class_ERR, audience_USR] always produces
|
|
162
|
-
// (class_INF OR class_ERR) AND audience_USR regardless of input order.
|
|
163
|
-
function buildFilterTree(filters: WsLogaccess.leftFilter[]): WsLogaccess.Filter {
|
|
164
|
-
const groupMap = new Map<string, WsLogaccess.leftFilter[]>();
|
|
165
|
-
for (const f of filters) {
|
|
166
|
-
const existing = groupMap.get(f.SearchField);
|
|
167
|
-
if (existing) existing.push(f); else groupMap.set(f.SearchField, [f]);
|
|
168
|
-
}
|
|
169
|
-
const groups = [...groupMap.values()];
|
|
170
|
-
|
|
171
|
-
if (groups.length === 0) {
|
|
172
|
-
return { leftFilter: { LogCategory: WsLogaccess.LogAccessType.All } as WsLogaccess.leftFilter };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const [firstGroup, ...remainingGroups] = groups;
|
|
176
|
-
const filter: WsLogaccess.Filter = {};
|
|
177
|
-
if (firstGroup.length === 1) {
|
|
178
|
-
filter.leftFilter = firstGroup[0];
|
|
179
|
-
} else {
|
|
180
|
-
filter.leftBinaryFilter = { BinaryLogFilter: [buildOrGroup(firstGroup)] };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if (remainingGroups.length === 0) return filter;
|
|
184
|
-
filter.Operator = WsLogaccess.LogAccessFilterOperator.AND;
|
|
185
|
-
if (remainingGroups.length === 1) {
|
|
186
|
-
const [secondGroup] = remainingGroups;
|
|
187
|
-
if (secondGroup.length === 1) {
|
|
188
|
-
filter.rightFilter = secondGroup[0] as WsLogaccess.rightFilter;
|
|
189
|
-
} else {
|
|
190
|
-
filter.rightBinaryFilter = { BinaryLogFilter: [buildOrGroup(secondGroup)] };
|
|
191
|
-
}
|
|
192
|
-
} else {
|
|
193
|
-
filter.rightBinaryFilter = { BinaryLogFilter: [buildAndChain(remainingGroups)] };
|
|
194
|
-
}
|
|
195
|
-
return filter;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export class LogaccessService extends LogaccessServiceBase {
|
|
199
|
-
|
|
200
|
-
protected _logAccessInfo: Promise<WsLogaccess.GetLogAccessInfoResponse>;
|
|
201
|
-
|
|
202
|
-
GetLogAccessInfo(request: WsLogaccess.GetLogAccessInfoRequest = {}): Promise<WsLogaccess.GetLogAccessInfoResponse> {
|
|
203
|
-
if (!this._logAccessInfo) {
|
|
204
|
-
this._logAccessInfo = super.GetLogAccessInfo(request);
|
|
205
|
-
}
|
|
206
|
-
return this._logAccessInfo;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
GetLogs(request: WsLogaccess.GetLogsRequest): Promise<WsLogaccess.GetLogsResponse> {
|
|
210
|
-
return super.GetLogs(request);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private convertLogLine(columnMap: Record<string, string>, line: any): LogLine {
|
|
214
|
-
const retVal: LogLine = {};
|
|
215
|
-
const fields = line?.fields ? Object.assign({}, ...line.fields) : null;
|
|
216
|
-
for (const key in columnMap) {
|
|
217
|
-
retVal[key] = fields ? fields[columnMap[key]] ?? "" : "";
|
|
218
|
-
}
|
|
219
|
-
return retVal;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async GetLogsEx(request: GetLogsExRequest): Promise<GetLogsExResponse> {
|
|
223
|
-
const logInfo = await this.GetLogAccessInfo();
|
|
224
|
-
const columnMap: Record<string, string> = {};
|
|
225
|
-
logInfo.Columns.Column.forEach(column => columnMap[column.LogType] = column.Name);
|
|
226
|
-
|
|
227
|
-
const filters = buildFilters(request, columnMap);
|
|
228
|
-
const range: Record<string, string> = {
|
|
229
|
-
StartDate: request.StartDate instanceof Date ? request.StartDate.toISOString() : new Date(0).toISOString()
|
|
230
|
-
};
|
|
231
|
-
if (request.EndDate instanceof Date) {
|
|
232
|
-
range.EndDate = request.EndDate.toISOString();
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const getLogsRequest: WsLogaccess.GetLogsRequest = {
|
|
236
|
-
Filter: buildFilterTree(filters),
|
|
237
|
-
Range: range,
|
|
238
|
-
LogLineStartFrom: request.LogLineStartFrom ?? 0,
|
|
239
|
-
LogLineLimit: request.LogLineLimit ?? 100,
|
|
240
|
-
SelectColumnMode: WsLogaccess.LogSelectColumnMode.DEFAULT,
|
|
241
|
-
Format: "JSON",
|
|
242
|
-
SortBy: {
|
|
243
|
-
SortCondition: [{
|
|
244
|
-
BySortType: WsLogaccess.SortColumType.ByDate,
|
|
245
|
-
ColumnName: "",
|
|
246
|
-
Direction: 0
|
|
247
|
-
}]
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
return this.GetLogs(getLogsRequest).then(response => {
|
|
252
|
-
try {
|
|
253
|
-
const logLines = JSON.parse(response.LogLines);
|
|
254
|
-
const lines = knownLogManagerTypes.has(logInfo.RemoteLogManagerType)
|
|
255
|
-
? (logLines.lines?.map((line: any) => this.convertLogLine(columnMap, line)) ?? [])
|
|
256
|
-
: (logger.warning(`Unknown RemoteLogManagerType: ${logInfo.RemoteLogManagerType}`), []);
|
|
257
|
-
return {
|
|
258
|
-
lines,
|
|
259
|
-
total: response.TotalLogLinesAvailable ?? 10000
|
|
260
|
-
};
|
|
261
|
-
} catch (e: any) {
|
|
262
|
-
logger.error(e.message ?? e);
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
lines: [],
|
|
266
|
-
total: 0
|
|
267
|
-
};
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
}
|
|
1
|
+
import { scopedLogger } from "@hpcc-js/util";
|
|
2
|
+
import { LogaccessServiceBase, WsLogaccess } from "./wsdl/ws_logaccess/v1.08/ws_logaccess.ts";
|
|
3
|
+
|
|
4
|
+
const logger = scopedLogger("@hpcc-js/comms/services/wsLogaccess.ts");
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
WsLogaccess
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export interface GetLogsExRequest {
|
|
11
|
+
audience?: string;
|
|
12
|
+
class?: string[];
|
|
13
|
+
workunits?: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
processid?: string;
|
|
16
|
+
logid?: string;
|
|
17
|
+
threadid?: string;
|
|
18
|
+
timestamp?: string;
|
|
19
|
+
components?: string;
|
|
20
|
+
instance?: string;
|
|
21
|
+
StartDate?: Date;
|
|
22
|
+
EndDate?: Date;
|
|
23
|
+
LogLineStartFrom: number,
|
|
24
|
+
LogLineLimit: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const enum LogType {
|
|
28
|
+
Disaster = "DIS",
|
|
29
|
+
Error = "ERR",
|
|
30
|
+
Warning = "WRN",
|
|
31
|
+
Information = "INF",
|
|
32
|
+
Progress = "PRO",
|
|
33
|
+
Metric = "MET"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const enum TargetAudience {
|
|
37
|
+
Operator = "OPR",
|
|
38
|
+
User = "USR",
|
|
39
|
+
Programmer = "PRO",
|
|
40
|
+
Audit = "ADT"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// properties here are "LogType" values in Ws_logaccess.GetLogAccessInfo
|
|
44
|
+
export interface LogLine {
|
|
45
|
+
audience?: string;
|
|
46
|
+
class?: string;
|
|
47
|
+
workunits?: string;
|
|
48
|
+
message?: string;
|
|
49
|
+
processid?: number;
|
|
50
|
+
logid?: string;
|
|
51
|
+
threadid?: number;
|
|
52
|
+
timestamp?: string;
|
|
53
|
+
components?: string;
|
|
54
|
+
instance?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface GetLogsExResponse {
|
|
58
|
+
lines: LogLine[],
|
|
59
|
+
total: number,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const knownLogManagerTypes = new Set(["azureloganalyticscurl", "elasticstack", "grafanacurl"]);
|
|
63
|
+
const logColumnTypeValues = new Set(Object.values(WsLogaccess.LogColumnType));
|
|
64
|
+
|
|
65
|
+
function getLogCategory(searchField: string): WsLogaccess.LogAccessType {
|
|
66
|
+
switch (searchField) {
|
|
67
|
+
case WsLogaccess.LogColumnType.workunits:
|
|
68
|
+
case "hpcc.log.jobid":
|
|
69
|
+
return WsLogaccess.LogAccessType.ByJobID;
|
|
70
|
+
case WsLogaccess.LogColumnType.audience:
|
|
71
|
+
case "hpcc.log.audience":
|
|
72
|
+
return WsLogaccess.LogAccessType.ByTargetAudience;
|
|
73
|
+
case WsLogaccess.LogColumnType.class:
|
|
74
|
+
case "hpcc.log.class":
|
|
75
|
+
return WsLogaccess.LogAccessType.ByLogType;
|
|
76
|
+
case WsLogaccess.LogColumnType.components:
|
|
77
|
+
case "kubernetes.container.name":
|
|
78
|
+
return WsLogaccess.LogAccessType.ByComponent;
|
|
79
|
+
default:
|
|
80
|
+
return WsLogaccess.LogAccessType.ByFieldName;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Explicit list of filter-bearing keys on GetLogsExRequest.
|
|
85
|
+
// Using an allowlist avoids accidentally treating control fields (StartDate, LogLineLimit, etc.)
|
|
86
|
+
// as log filters if the server ever returns a column whose name collides with them.
|
|
87
|
+
const FILTER_KEYS = ["audience", "class", "workunits", "message", "processid", "logid", "threadid", "timestamp", "components", "instance"] as const;
|
|
88
|
+
|
|
89
|
+
function buildFilters(request: GetLogsExRequest, columnMap: Record<string, string>): WsLogaccess.leftFilter[] {
|
|
90
|
+
const filters: WsLogaccess.leftFilter[] = [];
|
|
91
|
+
for (const key of FILTER_KEYS) {
|
|
92
|
+
const value = request[key];
|
|
93
|
+
if (value == null || value === "" || (Array.isArray(value) && value.length === 0)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (!(key in columnMap)) continue;
|
|
97
|
+
|
|
98
|
+
const isKnownLogType = logColumnTypeValues.has(key as WsLogaccess.LogColumnType);
|
|
99
|
+
let searchField: string = isKnownLogType ? key : columnMap[key];
|
|
100
|
+
const logCategory = getLogCategory(searchField);
|
|
101
|
+
if (logCategory === WsLogaccess.LogAccessType.ByFieldName) {
|
|
102
|
+
searchField = columnMap[key];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const appendWildcard = logCategory === WsLogaccess.LogAccessType.ByComponent;
|
|
106
|
+
const rawValues: string[] = Array.isArray(value) ? value : [value as string];
|
|
107
|
+
for (const raw of rawValues) {
|
|
108
|
+
filters.push({
|
|
109
|
+
LogCategory: logCategory,
|
|
110
|
+
SearchField: searchField,
|
|
111
|
+
// append wildcard to end of search value to include ephemeral
|
|
112
|
+
// containers that aren't listed in ECL Watch's filters
|
|
113
|
+
SearchByValue: appendWildcard ? raw + "*" : raw
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return filters;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Builds a left-leaning OR chain from filters that share the same SearchField.
|
|
121
|
+
function buildOrGroup(group: WsLogaccess.leftFilter[]): WsLogaccess.BinaryLogFilter {
|
|
122
|
+
const root: WsLogaccess.BinaryLogFilter = { leftFilter: group[0] } as WsLogaccess.BinaryLogFilter;
|
|
123
|
+
let node = root;
|
|
124
|
+
for (let i = 1; i < group.length; i++) {
|
|
125
|
+
node.Operator = WsLogaccess.LogAccessFilterOperator.OR;
|
|
126
|
+
if (i === group.length - 1) {
|
|
127
|
+
node.rightFilter = group[i] as WsLogaccess.rightFilter;
|
|
128
|
+
} else {
|
|
129
|
+
node.rightBinaryFilter = { BinaryLogFilter: [{ leftFilter: group[i] } as WsLogaccess.BinaryLogFilter] };
|
|
130
|
+
node = node.rightBinaryFilter.BinaryLogFilter[0];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return root;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Recursively AND-chains two or more groups into a BinaryLogFilter (used for nesting beyond depth 1).
|
|
137
|
+
function buildAndChain(groups: WsLogaccess.leftFilter[][]): WsLogaccess.BinaryLogFilter {
|
|
138
|
+
const [firstGroup, ...remainingGroups] = groups;
|
|
139
|
+
const node: WsLogaccess.BinaryLogFilter = {} as WsLogaccess.BinaryLogFilter;
|
|
140
|
+
if (firstGroup.length === 1) {
|
|
141
|
+
node.leftFilter = firstGroup[0];
|
|
142
|
+
} else {
|
|
143
|
+
node.leftBinaryFilter = { BinaryLogFilter: [buildOrGroup(firstGroup)] };
|
|
144
|
+
}
|
|
145
|
+
if (remainingGroups.length === 0) return node;
|
|
146
|
+
node.Operator = WsLogaccess.LogAccessFilterOperator.AND;
|
|
147
|
+
if (remainingGroups.length === 1) {
|
|
148
|
+
const [secondGroup] = remainingGroups;
|
|
149
|
+
if (secondGroup.length === 1) {
|
|
150
|
+
node.rightFilter = secondGroup[0] as WsLogaccess.rightFilter;
|
|
151
|
+
} else {
|
|
152
|
+
node.rightBinaryFilter = { BinaryLogFilter: [buildOrGroup(secondGroup)] };
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
node.rightBinaryFilter = { BinaryLogFilter: [buildAndChain(remainingGroups)] };
|
|
156
|
+
}
|
|
157
|
+
return node;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Groups filters by SearchField, OR-chains each group, then AND-chains the groups together.
|
|
161
|
+
// This ensures e.g. [class_INF, class_ERR, audience_USR] always produces
|
|
162
|
+
// (class_INF OR class_ERR) AND audience_USR regardless of input order.
|
|
163
|
+
function buildFilterTree(filters: WsLogaccess.leftFilter[]): WsLogaccess.Filter {
|
|
164
|
+
const groupMap = new Map<string, WsLogaccess.leftFilter[]>();
|
|
165
|
+
for (const f of filters) {
|
|
166
|
+
const existing = groupMap.get(f.SearchField);
|
|
167
|
+
if (existing) existing.push(f); else groupMap.set(f.SearchField, [f]);
|
|
168
|
+
}
|
|
169
|
+
const groups = [...groupMap.values()];
|
|
170
|
+
|
|
171
|
+
if (groups.length === 0) {
|
|
172
|
+
return { leftFilter: { LogCategory: WsLogaccess.LogAccessType.All } as WsLogaccess.leftFilter };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const [firstGroup, ...remainingGroups] = groups;
|
|
176
|
+
const filter: WsLogaccess.Filter = {};
|
|
177
|
+
if (firstGroup.length === 1) {
|
|
178
|
+
filter.leftFilter = firstGroup[0];
|
|
179
|
+
} else {
|
|
180
|
+
filter.leftBinaryFilter = { BinaryLogFilter: [buildOrGroup(firstGroup)] };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (remainingGroups.length === 0) return filter;
|
|
184
|
+
filter.Operator = WsLogaccess.LogAccessFilterOperator.AND;
|
|
185
|
+
if (remainingGroups.length === 1) {
|
|
186
|
+
const [secondGroup] = remainingGroups;
|
|
187
|
+
if (secondGroup.length === 1) {
|
|
188
|
+
filter.rightFilter = secondGroup[0] as WsLogaccess.rightFilter;
|
|
189
|
+
} else {
|
|
190
|
+
filter.rightBinaryFilter = { BinaryLogFilter: [buildOrGroup(secondGroup)] };
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
filter.rightBinaryFilter = { BinaryLogFilter: [buildAndChain(remainingGroups)] };
|
|
194
|
+
}
|
|
195
|
+
return filter;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export class LogaccessService extends LogaccessServiceBase {
|
|
199
|
+
|
|
200
|
+
protected _logAccessInfo: Promise<WsLogaccess.GetLogAccessInfoResponse>;
|
|
201
|
+
|
|
202
|
+
GetLogAccessInfo(request: WsLogaccess.GetLogAccessInfoRequest = {}): Promise<WsLogaccess.GetLogAccessInfoResponse> {
|
|
203
|
+
if (!this._logAccessInfo) {
|
|
204
|
+
this._logAccessInfo = super.GetLogAccessInfo(request);
|
|
205
|
+
}
|
|
206
|
+
return this._logAccessInfo;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
GetLogs(request: WsLogaccess.GetLogsRequest): Promise<WsLogaccess.GetLogsResponse> {
|
|
210
|
+
return super.GetLogs(request);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private convertLogLine(columnMap: Record<string, string>, line: any): LogLine {
|
|
214
|
+
const retVal: LogLine = {};
|
|
215
|
+
const fields = line?.fields ? Object.assign({}, ...line.fields) : null;
|
|
216
|
+
for (const key in columnMap) {
|
|
217
|
+
retVal[key] = fields ? fields[columnMap[key]] ?? "" : "";
|
|
218
|
+
}
|
|
219
|
+
return retVal;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async GetLogsEx(request: GetLogsExRequest): Promise<GetLogsExResponse> {
|
|
223
|
+
const logInfo = await this.GetLogAccessInfo();
|
|
224
|
+
const columnMap: Record<string, string> = {};
|
|
225
|
+
logInfo.Columns.Column.forEach(column => columnMap[column.LogType] = column.Name);
|
|
226
|
+
|
|
227
|
+
const filters = buildFilters(request, columnMap);
|
|
228
|
+
const range: Record<string, string> = {
|
|
229
|
+
StartDate: request.StartDate instanceof Date ? request.StartDate.toISOString() : new Date(0).toISOString()
|
|
230
|
+
};
|
|
231
|
+
if (request.EndDate instanceof Date) {
|
|
232
|
+
range.EndDate = request.EndDate.toISOString();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const getLogsRequest: WsLogaccess.GetLogsRequest = {
|
|
236
|
+
Filter: buildFilterTree(filters),
|
|
237
|
+
Range: range,
|
|
238
|
+
LogLineStartFrom: request.LogLineStartFrom ?? 0,
|
|
239
|
+
LogLineLimit: request.LogLineLimit ?? 100,
|
|
240
|
+
SelectColumnMode: WsLogaccess.LogSelectColumnMode.DEFAULT,
|
|
241
|
+
Format: "JSON",
|
|
242
|
+
SortBy: {
|
|
243
|
+
SortCondition: [{
|
|
244
|
+
BySortType: WsLogaccess.SortColumType.ByDate,
|
|
245
|
+
ColumnName: "",
|
|
246
|
+
Direction: 0
|
|
247
|
+
}]
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
return this.GetLogs(getLogsRequest).then(response => {
|
|
252
|
+
try {
|
|
253
|
+
const logLines = JSON.parse(response.LogLines);
|
|
254
|
+
const lines = knownLogManagerTypes.has(logInfo.RemoteLogManagerType)
|
|
255
|
+
? (logLines.lines?.map((line: any) => this.convertLogLine(columnMap, line)) ?? [])
|
|
256
|
+
: (logger.warning(`Unknown RemoteLogManagerType: ${logInfo.RemoteLogManagerType}`), []);
|
|
257
|
+
return {
|
|
258
|
+
lines,
|
|
259
|
+
total: response.TotalLogLinesAvailable ?? 10000
|
|
260
|
+
};
|
|
261
|
+
} catch (e: any) {
|
|
262
|
+
logger.error(e.message ?? e);
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
lines: [],
|
|
266
|
+
total: 0
|
|
267
|
+
};
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|