Skip to content

Commit 38b9145

Browse files
committed
feat: Add normalized global metrics support
Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
1 parent e26c952 commit 38b9145

3 files changed

Lines changed: 138 additions & 21 deletions

File tree

packages/comms/index.html

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,20 @@
1616
margin-top: 50px;
1717
}
1818

19-
#placeholder {
19+
.placeholder {
2020
width: 100%;
21-
height: 500px;
21+
height: 640px;
2222
background-color: #fff;
23-
margin-top: 20px;
23+
margin: 20px auto;
24+
padding: 20px;
25+
box-sizing: border-box;
26+
overflow: auto;
27+
white-space: pre-wrap;
28+
font-family: 'Courier New', monospace;
29+
font-size: 12px;
30+
line-height: 1;
31+
border: 1px solid #ddd;
32+
border-radius: 4px;
2433
}
2534
</style>
2635

@@ -29,25 +38,18 @@
2938

3039
<body>
3140
<h1>ESM Quick Test</h1>
32-
<div id="placeholder"></div>
41+
<div id="wuPlaceholder" class="placeholder"></div>
3342
<script type="module">
34-
import { Workunit } from "./src/index.browser.ts";
35-
36-
Workunit.submit({ baseUrl: "http://localhost:8010" }, "hthor", "'Hello and Welcome!';")
37-
.then((wu) => {
38-
return wu.watchUntilComplete();
39-
}).then((wu) => {
40-
return wu.fetchResults().then((results) => {
41-
return results[0].fetchRows();
42-
}).then((rows) => {
43-
return wu;
44-
});
45-
}).then((wu) => {
46-
return wu.delete().then(() => wu);
47-
}).then(wu => {
48-
}).catch((e) => {
49-
console.error(e);
50-
});
43+
import { testWUDetailsMeta } from "./tests/index.ts";
44+
45+
testWUDetailsMeta("wuPlaceholder");
46+
</script>
47+
48+
<div id="placeholder" class="placeholder"></div>
49+
<script type="module">
50+
import { testSMCGlobalMetrics } from "./tests/index.ts";
51+
52+
testSMCGlobalMetrics("placeholder");
5153
</script>
5254
</body>
5355

packages/comms/src/services/wsSMC.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
1+
import { timeParse } from "@hpcc-js/common";
12
import { SMCServiceBase, WsSMC } from "./wsdl/WsSMC/v1.28/WsSMC.ts";
23
import { IOptions } from "../connection.ts";
34

45
export {
56
WsSMC
67
};
78

9+
const dateParser = timeParse("%Y%m%d%H");
10+
11+
function isNumeric(value: any): boolean {
12+
return typeof value === "number" || (typeof value === "string" && value.trim() !== "" && !isNaN(+value));
13+
}
14+
15+
export interface NormalisedGlobalMetric {
16+
Category: string;
17+
Start: Date;
18+
End: Date;
19+
dimensions: { [key: string]: any };
20+
stats: { [key: string]: any };
21+
}
22+
823
export class SMCService extends SMCServiceBase {
924

1025
connectionOptions(): IOptions {
@@ -21,4 +36,45 @@ export class SMCService extends SMCServiceBase {
2136
};
2237
});
2338
}
39+
40+
protected parseGlobalMetric(name: string, value: any): any {
41+
// Known Prefixes: Cost, Critical, Definition, Disk, Distribute, Ecl, Enum, Id, Interface, Is, Library, Load, Match, Meta, Num, Original, Output, Patch, Per, Persist, Predicted, Record, Section, Service, Signed, Size, Source, Spill, Target, Time, Updated, When
42+
if (name.startsWith("Cost")) {
43+
return +value / 1000000;
44+
} else if (name.startsWith("Date")) {
45+
return dateParser(value);
46+
} else if (name.startsWith("Num")) {
47+
return +value;
48+
} else if (name.startsWith("Time")) {
49+
return +value / 1000000000;
50+
} else if (name.startsWith("When")) {
51+
return new Date(+value / 1000).toISOString();
52+
} else if (isNumeric(value)) {
53+
return +value;
54+
}
55+
return value;
56+
}
57+
58+
GetNormalisedGlobalMetrics(request: Partial<WsSMC.GetGlobalMetrics>): Promise<NormalisedGlobalMetric[]> {
59+
return super.GetGlobalMetrics(request).then(response => {
60+
const retVal: NormalisedGlobalMetric[] = [];
61+
for (const metric of response?.GlobalMetrics?.GlobalMetric || []) {
62+
const row: NormalisedGlobalMetric = {
63+
Category: metric.Category,
64+
Start: this.parseGlobalMetric("Date", metric.DateTimeRange?.Start),
65+
End: this.parseGlobalMetric("Date", metric.DateTimeRange?.End),
66+
dimensions: {},
67+
stats: {}
68+
};
69+
for (const dimension of metric.Dimensions?.Dimension || []) {
70+
row.dimensions[dimension.Name] = dimension.Value;
71+
}
72+
for (const stat of metric.Stats?.Stat || []) {
73+
row.stats[stat.Name] = this.parseGlobalMetric(stat.Name, stat.Value);
74+
}
75+
retVal.push(row);
76+
}
77+
return retVal;
78+
});
79+
}
2480
}

packages/comms/tests/index.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { SMCService, WorkunitsService } from "../src/index.browser.ts";
2+
3+
export function testWUDetailsMeta(placeholder: string) {
4+
const wuService = new WorkunitsService({ baseUrl: "http://localhost:8010" });
5+
const wuPlaceholder = document.getElementById(placeholder);
6+
wuService.WUDetailsMeta({}).then(response => {
7+
const prefixSet = new Set<string>();
8+
response?.Properties?.Property.forEach(field => {
9+
if (field.Name) {
10+
// Find the first capital letter after the first character
11+
for (let i = 1; i < field.Name.length; i++) {
12+
if (field.Name[i] === field.Name[i].toUpperCase() && field.Name[i] !== field.Name[i].toLowerCase()) {
13+
prefixSet.add(field.Name.substring(0, i));
14+
break;
15+
}
16+
}
17+
}
18+
});
19+
console.info("WUDetailsMeta Response:", response);
20+
console.info("Prefixes:", Array.from(prefixSet).sort());
21+
if (wuPlaceholder) {
22+
wuPlaceholder.textContent = JSON.stringify(Array.from(prefixSet).sort(), null, 2) + "\n\n" + JSON.stringify(response, null, 2);
23+
}
24+
}).catch(err => {
25+
console.error("Error calling WUDetailsMeta:", err);
26+
if (wuPlaceholder) {
27+
wuPlaceholder.textContent = JSON.stringify(err, null, 2);
28+
}
29+
});
30+
31+
}
32+
33+
export function testSMCGlobalMetrics(placeholder: string) {
34+
const service = new SMCService({ baseUrl: "http://localhost:8010" });
35+
const placeholderElement = document.getElementById(placeholder);
36+
37+
const end = new Date();
38+
const start = new Date(end);
39+
start.setUTCMonth(start.getUTCMonth() - 1);
40+
start.setUTCHours(0, 0, 0, 0);
41+
42+
const request = {
43+
DateTimeRange: {
44+
Start: start.toISOString(),
45+
End: end.toISOString()
46+
}
47+
};
48+
service.GetNormalisedGlobalMetrics(request).then(response => {
49+
console.info("GetNormalisedGlobalMetrics Response:", response);
50+
if (placeholderElement) {
51+
placeholderElement.textContent = JSON.stringify(response, null, 2);
52+
}
53+
}).catch(err => {
54+
console.error("Error calling GetNormalisedGlobalMetrics:", err);
55+
if (placeholderElement) {
56+
placeholderElement.textContent = JSON.stringify(err, null, 2);
57+
}
58+
});
59+
}

0 commit comments

Comments
 (0)