Skip to content

Commit ff223b5

Browse files
authored
fix(EventHub): refactor log handler (#88)
1 parent f3e5cac commit ff223b5

File tree

4 files changed

+172
-17
lines changed

4 files changed

+172
-17
lines changed

EventHub/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### 3.6.1 / 16 Dec 2024
2+
[REFACTOR]
3+
* Remove `handleEventHubMessage` wrapper function
4+
* Inline `writeLog` calls directly in the EventHub trigger
5+
16
### 3.6.0 / 15 Dec 2024
27
[FEATURE] Dynamic Application/Subsystem Selector ARM Template Parameters:
38
* Added `CoralogixApplicationSelector` ARM template parameter for dynamic application name resolution

EventHub/EventHub/index.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* @link https://coralogix.com/
77
* @copyright Coralogix Ltd.
88
* @licence Apache-2.0
9-
* @version 3.2.0
9+
* @version 3.6.1
1010
* @since 1.0.0
1111
*/
1212

@@ -291,25 +291,35 @@ export function handleLogEntries(
291291
return entries;
292292
}
293293

294-
function handleEventHubMessage(context: InvocationContext, message: any, threadId: string): void {
295-
let entries: any[];
294+
/**
295+
* @description Unwrap an EventHub message into individual log entries.
296+
* @param message - Raw EventHub message (string, object, or any)
297+
* @returns Array of individual log entries to process
298+
*/
299+
export function unwrapEventHubMessage(message: any): any[] {
300+
let parsed = message;
301+
if (typeof message === "string") {
302+
try {
303+
parsed = JSON.parse(message);
304+
} catch {
305+
parsed = message;
306+
}
307+
}
296308

297309
if (
298-
message &&
299-
typeof message === "object" &&
300-
!Array.isArray(message) &&
301-
Array.isArray((message as any).records)
310+
parsed &&
311+
typeof parsed === "object" &&
312+
!Array.isArray(parsed) &&
313+
Array.isArray(parsed.records)
302314
) {
303-
entries = (message as any).records;
304-
} else {
305-
const content =
306-
message && typeof message === "object" && "body" in message ? (message as any).body : message;
307-
entries = [content];
315+
return parsed.records;
308316
}
309317

310-
entries.forEach((entry, idx) => {
311-
writeLog(context, entry, threadId, idx);
312-
});
318+
if (parsed && typeof parsed === "object" && "body" in parsed) {
319+
return [parsed.body];
320+
}
321+
322+
return [message];
313323
}
314324

315325
/* -------------------------------------------------------------------------- */
@@ -327,7 +337,10 @@ const eventHubTrigger = async function (context: InvocationContext, events: any)
327337

328338
events.forEach((event, index) => {
329339
try {
330-
handleEventHubMessage(context, event, threadId);
340+
const entries = unwrapEventHubMessage(event);
341+
entries.forEach((entry, idx) => {
342+
writeLog(context, entry, threadId, idx);
343+
});
331344
} catch (msgError: any) {
332345
context.log(`Failed to process message ${index}: ${msgError.message}`);
333346
}

EventHub/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "coralogix-azure-serverless",
33
"title": "Azure Functions for integration with Coralogix",
4-
"version": "3.6.0",
4+
"version": "3.6.1",
55
"description": "Azure Functions Set for integration with Coralogix",
66
"homepage": "https://coralogix.com",
77
"license": "Apache-2.0",

EventHub/tests/index.test.ts

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type LogModule = {
1010
detectLogFormat: typeof import("../EventHub/index").detectLogFormat;
1111
LogFormat: typeof import("../EventHub/index").LogFormat;
1212
handleLogEntries: typeof import("../EventHub/index").handleLogEntries;
13+
unwrapEventHubMessage: typeof import("../EventHub/index").unwrapEventHubMessage;
1314
};
1415

1516
type EnvConfig = {
@@ -53,6 +54,142 @@ function loadLogModule(env: EnvConfig = {}): LogModule {
5354
return mod!;
5455
}
5556

57+
describe("unwrapEventHubMessage - eventHub message parsing", () => {
58+
describe("JSON string parsing", () => {
59+
it("should parse JSON string into object", () => {
60+
const { unwrapEventHubMessage } = loadLogModule();
61+
const jsonString = JSON.stringify({ category: "Test", message: "Hello" });
62+
63+
const result = unwrapEventHubMessage(jsonString);
64+
65+
expect(result).toHaveLength(1);
66+
expect(result[0]).toBe(jsonString);
67+
});
68+
69+
it("should keep invalid JSON as string", () => {
70+
const { unwrapEventHubMessage } = loadLogModule();
71+
const invalidJson = "not valid json {";
72+
73+
const result = unwrapEventHubMessage(invalidJson);
74+
75+
expect(result).toHaveLength(1);
76+
expect(result[0]).toBe(invalidJson);
77+
});
78+
79+
it("should keep plain text as-is", () => {
80+
const { unwrapEventHubMessage } = loadLogModule();
81+
const plainText = "2025-01-01 INFO Application started";
82+
83+
const result = unwrapEventHubMessage(plainText);
84+
85+
expect(result).toHaveLength(1);
86+
expect(result[0]).toBe(plainText);
87+
});
88+
});
89+
90+
describe("records array wrapper", () => {
91+
it("should unwrap records array from object", () => {
92+
const { unwrapEventHubMessage } = loadLogModule();
93+
const input = {
94+
records: [
95+
{ id: 1, message: "first" },
96+
{ id: 2, message: "second" },
97+
{ id: 3, message: "third" },
98+
],
99+
};
100+
101+
const result = unwrapEventHubMessage(input);
102+
103+
expect(result).toHaveLength(3);
104+
expect(result[0].id).toBe(1);
105+
expect(result[1].id).toBe(2);
106+
expect(result[2].id).toBe(3);
107+
});
108+
109+
it("should unwrap records array from JSON string", () => {
110+
const { unwrapEventHubMessage } = loadLogModule();
111+
const jsonString = JSON.stringify({
112+
records: [
113+
{ id: 1, message: "first" },
114+
{ id: 2, message: "second" },
115+
],
116+
});
117+
118+
const result = unwrapEventHubMessage(jsonString);
119+
120+
expect(result).toHaveLength(2);
121+
expect(result[0].id).toBe(1);
122+
expect(result[1].id).toBe(2);
123+
});
124+
125+
it("should handle empty records array", () => {
126+
const { unwrapEventHubMessage } = loadLogModule();
127+
const input = { records: [] };
128+
129+
const result = unwrapEventHubMessage(input);
130+
131+
expect(result).toHaveLength(0);
132+
});
133+
134+
it("should handle single record in array", () => {
135+
const { unwrapEventHubMessage } = loadLogModule();
136+
const input = {
137+
records: [{ id: 1, message: "only one" }],
138+
};
139+
140+
const result = unwrapEventHubMessage(input);
141+
142+
expect(result).toHaveLength(1);
143+
expect(result[0].id).toBe(1);
144+
});
145+
});
146+
147+
describe("body property wrapper", () => {
148+
it("should unwrap object body", () => {
149+
const { unwrapEventHubMessage } = loadLogModule();
150+
const input = {
151+
body: { event: "user_login", userId: 123 },
152+
};
153+
154+
const result = unwrapEventHubMessage(input);
155+
156+
expect(result).toHaveLength(1);
157+
expect(result[0].event).toBe("user_login");
158+
});
159+
160+
it("should unwrap string body", () => {
161+
const { unwrapEventHubMessage } = loadLogModule();
162+
const input = {
163+
body: "plain text log message",
164+
};
165+
166+
const result = unwrapEventHubMessage(input);
167+
168+
expect(result).toHaveLength(1);
169+
expect(result[0]).toBe("plain text log message");
170+
});
171+
});
172+
173+
describe("Edge cases", () => {
174+
it("should preserve nested objects in records", () => {
175+
const { unwrapEventHubMessage } = loadLogModule();
176+
const jsonString = JSON.stringify({
177+
records: [
178+
{
179+
id: 1,
180+
nested: { deep: { value: 42 } },
181+
},
182+
],
183+
});
184+
185+
const result = unwrapEventHubMessage(jsonString);
186+
187+
expect(result).toHaveLength(1);
188+
expect(result[0].nested.deep.value).toBe(42);
189+
});
190+
});
191+
});
192+
56193
describe("Application / Subsystem selector resolution", () => {
57194
it("uses default when selector is not set", () => {
58195
const mod = loadLogModule({

0 commit comments

Comments
 (0)