diff --git a/azure/activity_logs_monitoring/index.js b/azure/activity_logs_monitoring/index.js index d7bde7d3..a4ce4cb4 100644 --- a/azure/activity_logs_monitoring/index.js +++ b/azure/activity_logs_monitoring/index.js @@ -381,7 +381,7 @@ class EventhubLogHandler { this.records.push(originalRecord); } } else { - this.records.push(originalRecord); + this.records.push(this.fixPropertiesJsonString(originalRecord)); } } else { record = this.addTagsToStringLog(record); @@ -389,6 +389,24 @@ class EventhubLogHandler { } } + fixPropertiesJsonString(record) { + // Check if properties field is a malformed JSON String + if (Object.hasOwn(record, 'properties') && (typeof record.properties === 'string') && (record.properties.includes("':'"))) { + try { + // If the check is true, find and replace single quotes + // with double quotes, to make a proper JSON + // which is then converted into a JSON Object + record.properties = JSON.parse(record.properties.replace(/'/g, '"')); + return record; + } catch { + this.context.error('Unable to fix properties field to JSON Object'); + return record; + } + } else { + return record; + } + } + handleLogs(logs) { let logsType = this.getLogFormat(logs); switch (logsType) { diff --git a/azure/test/activity_logs_monitoring.test.js b/azure/test/activity_logs_monitoring.test.js index ecb2d5d0..fe49ccd0 100644 --- a/azure/test/activity_logs_monitoring.test.js +++ b/azure/test/activity_logs_monitoring.test.js @@ -818,3 +818,84 @@ describe('Log Splitting', function() { }); }); }); +describe('EventhubLogHandler Fix Properties Json String', function() { + + beforeEach(function() { + this.forwarder = setUp(); + }); + + it('parses properties string with single quotes into object', function() { + const record = { properties: "{'key':'value'}" }; + const result = this.forwarder.fixPropertiesJsonString(record); + + const expectedProperties = { properties: { key: "value" } }; + + assert.deepEqual( + expectedProperties, + result + ); + assert.equal( + 'object', + typeof result.properties + ) + }); + + it('parses object that doesnt have properties', function() { + const record = { hostname: "server_name", subObject: { key:"value"} }; + const result = this.forwarder.fixPropertiesJsonString(record); + + assert.deepEqual( + record, + result + ); + assert.equal( + 'object', + typeof result + ) + }); + + it('parses properties string with nested objects', function() { + const record = { properties: "{'key':'value','subObj':{ 'subKey' : 'subValue' }}" }; + const result = this.forwarder.fixPropertiesJsonString(record); + + const expectedProperties = { properties: { key: "value", subObj: { subKey: "subValue"} } }; + + assert.deepEqual( + expectedProperties, + result + ); + assert.equal( + 'object', + typeof result.properties + ) + }); + + it("leaves properties string unchanged when it doesn't match the malformed pattern", function() { + const record = { properties: 'some plain string without colons' }; + const result = this.forwarder.fixPropertiesJsonString(record); + + assert.deepEqual( + record, + result + ); + assert.equal( + 'string', + typeof result.properties + ) + }); + + it('logs an error and returns original record when replacement results in invalid JSON', function() { + // includes the "':'" marker so the function attempts replacement, but JSON remains invalid + const badRecord = { properties: "Look i know i shouldn't but, i will do this ':' " }; + const result = this.forwarder.fixPropertiesJsonString(badRecord); + + assert.deepEqual( + badRecord, + result + ); + assert.equal( + 'string', + typeof result.properties + ) + }); +});