From 3022538cac5abdf682dea26a88d014fe7831c52e Mon Sep 17 00:00:00 2001 From: ndesai Date: Wed, 5 Jun 2024 11:46:50 -0500 Subject: [PATCH] feat:added log forwarding for cordova. --- plugin.xml | 5 +- src/android/NewRelicCordovaPlugin.java | 88 +++++++++++++++- src/ios/NewRelicCordovaPlugin.h | 18 ++++ src/ios/NewRelicCordovaPlugin.m | 81 ++++++++++++++ www/js/newrelic.js | 139 ++++++++++++++++++++++++- 5 files changed, 326 insertions(+), 5 deletions(-) diff --git a/plugin.xml b/plugin.xml index 83e433b..4207b86 100644 --- a/plugin.xml +++ b/plugin.xml @@ -33,6 +33,8 @@ + + @@ -59,6 +61,7 @@ + @@ -118,7 +121,7 @@ - + strToLogLevel = new HashMap<>(); strToLogLevel.put("ERROR", AgentLog.ERROR); strToLogLevel.put("WARNING", AgentLog.WARN); @@ -99,7 +106,8 @@ public void initialize(CordovaInterface cordova, CordovaWebView webView) { String collectorAddress = preferences.getString("collector_address", null); String crashCollectorAddress = preferences.getString("crash_collector_address", null); - + LogReporting.setLogLevel(LogLevel.VERBOSE); + NewRelic.setEntityGuid("MXxNT0JJTEV8QVBQTElDQVRJT058NjAxMzQ0MTMy"); NewRelic newRelic = NewRelic.withApplicationToken(appToken) .withApplicationFramework(ApplicationFramework.Cordova, pluginVersion) .withLoggingEnabled(preferences.getString("logging_enabled", "true").toLowerCase().equals("true")) @@ -477,7 +485,71 @@ public void run() { } headers.put("headersList", array); callbackContext.success(headers); + break; } + case "logInfo": { + final String message = args.getString(0); + NewRelic.logInfo(message); + break; + } + case "logError": { + final String message = args.getString(0); + NewRelic.logError(message); + break; + } + case "logWarn": { + final String message = args.getString(0); + NewRelic.logWarning(message); + break; + } + case "logVerbose": { + final String message = args.getString(0); + NewRelic.logVerbose(message); + break; + } + case "logDebug": { + final String message = args.getString(0); + NewRelic.logDebug(message); + break; + } + case "log" : { + final String message = args.getString(0); + final String level = args.getString(1); + + if(message == null || message.isEmpty()) { + Log.w(TAG, "Empty message given to log"); + return false; + } + + if(level == null) { + Log.w(TAG, "Null logLevel given to log"); + return false; + } + + Map strToLogLevel = new HashMap<>(); + strToLogLevel.put("ERROR", LogLevel.ERROR); + strToLogLevel.put("WARNING", LogLevel.WARN); + strToLogLevel.put("INFO", LogLevel.INFO); + strToLogLevel.put("VERBOSE", LogLevel.VERBOSE); + strToLogLevel.put("AUDIT", LogLevel.DEBUG); + + LogLevel logLevel = strToLogLevel.get(level); + + NewRelic.log(logLevel, message); + break; + } + case "logAll": { + final String message = args.getString(0); + final JSONObject attributesASJson = args.getJSONObject(1); + logAttributesFromJson(attributesASJson, message); + break; + } + case "logAttributes": { + final JSONObject attributesASJson = args.getJSONObject(0); + logAttributesFromJson(attributesASJson, null); + break; + } + } } catch (Exception e) { @@ -488,6 +560,18 @@ public void run() { return true; } + private void logAttributesFromJson(JSONObject attributesAsJson, String message) { + final Map attributes = new Gson().fromJson(String.valueOf(attributesAsJson), Map.class); + if(attributes == null) { + Log.e(TAG,"Null attributes given to logAttributes"); + return; + } + if (message != null) { + attributes.put("message", message); + } + NewRelic.logAttributes(attributes); + } + protected static final class NRTraceConstants { public static final String TRACE_PARENT = "traceparent"; diff --git a/src/ios/NewRelicCordovaPlugin.h b/src/ios/NewRelicCordovaPlugin.h index aaaf8f8..0165a21 100644 --- a/src/ios/NewRelicCordovaPlugin.h +++ b/src/ios/NewRelicCordovaPlugin.h @@ -67,4 +67,22 @@ - (void)generateDistributedTracingHeaders:(CDVInvokedUrlCommand *)command; +- (void)logInfo:(CDVInvokedUrlCommand *)command; + +- (void)logError:(CDVInvokedUrlCommand *)command; + +- (void)logWarn:(CDVInvokedUrlCommand *)command; + +- (void)logDebug:(CDVInvokedUrlCommand *)command; + +- (void)logVerbose:(CDVInvokedUrlCommand *)command; + +- (void)log:(CDVInvokedUrlCommand *)command; + +- (void)logAttributes:(CDVInvokedUrlCommand *)command; + +- (void)logAll:(CDVInvokedUrlCommand *)command; + + + @end diff --git a/src/ios/NewRelicCordovaPlugin.m b/src/ios/NewRelicCordovaPlugin.m index 54c685d..ff3285f 100644 --- a/src/ios/NewRelicCordovaPlugin.m +++ b/src/ios/NewRelicCordovaPlugin.m @@ -66,6 +66,12 @@ - (void)pluginInitialize if (![self shouldDisableFeature:config[@"new_event_system_enabled"]]) { [NewRelic enableFeatures:NRFeatureFlag_NewEventSystem]; } + + if (![self shouldDisableFeature:config[@"log_reporting_enabled"]]) { + [NewRelic enableFeatures:NRFeatureFlag_LogReporting]; + } else { + [NewRelic disableFeatures:NRFeatureFlag_LogReporting]; + } // Set log level depending on loggingEnabled and logLevel NRLogLevels logLevel = NRLogLevelWarning; @@ -92,6 +98,8 @@ - (void)pluginInitialize [NewRelic setPlatform:NRMAPlatform_Cordova]; [NewRelic setPlatformVersion:config[@"plugin_version"]]; + [NRLogger setLogTargets: NRLogTargetFile]; + [NRLogger setLogEntityGuid:@"MXxNT0JJTEV8QVBQTElDQVRJT058NjAxMzQ0MTMy"]; if ([self isEmptyConfigParameter:collectorAddress] && [self isEmptyConfigParameter:crashCollectorAddress]) { [NewRelic startWithApplicationToken:applicationToken]; @@ -451,5 +459,78 @@ - (void)generateDistributedTracingHeaders:(CDVInvokedUrlCommand *)command { [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId]; } +- (void)logInfo:(CDVInvokedUrlCommand *)command { + NSString* message = [command.arguments objectAtIndex:0]; + [NewRelic logInfo:message]; + +} + +- (void)logError:(CDVInvokedUrlCommand *)command { + NSString* message = [command.arguments objectAtIndex:0]; + [NewRelic logError:message]; +} + +- (void)logWarn:(CDVInvokedUrlCommand *)command { + NSString* message = [command.arguments objectAtIndex:0]; + [NewRelic logWarning:message]; +} + +- (void)logDebug:(CDVInvokedUrlCommand *)command { + NSString* message = [command.arguments objectAtIndex:0]; + [NewRelic logDebug:message]; +} + +- (void)logVerbose:(CDVInvokedUrlCommand *)command { + NSString* message = [command.arguments objectAtIndex:0]; + [NewRelic logVerbose:message]; +} + +- (void)log:(CDVInvokedUrlCommand *)command { + NSString* level = [command.arguments objectAtIndex:0]; + NSString* message = [command.arguments objectAtIndex:1]; + + if(message == nil || message.length == 0) { + return; + } + + if(level == nil || level.length == 0) { + return; + } + + NRLogLevels logLevel = NRLogLevelWarning; + NSDictionary *logDict = @{ + @"ERROR": [NSNumber numberWithInt:NRLogLevelError], + @"WARNING": [NSNumber numberWithInt:NRLogLevelWarning], + @"INFO": [NSNumber numberWithInt:NRLogLevelInfo], + @"VERBOSE": [NSNumber numberWithInt:NRLogLevelVerbose], + @"AUDIT": [NSNumber numberWithInt:NRLogLevelAudit], + }; + if ([logDict objectForKey:[level uppercaseString]]) { + NSString* configLogLevel = [level uppercaseString]; + NSNumber* newLogLevel = [logDict valueForKey:configLogLevel]; + logLevel = [newLogLevel intValue]; + } + + [NewRelic log:message level:logLevel]; +} + +- (void)logAttributes:(CDVInvokedUrlCommand *)command { + NSDictionary *attributes = [command.arguments objectAtIndex:0]; + + [NewRelic logAll:attributes]; + +} + +- (void)logAll:(CDVInvokedUrlCommand *)command { + + NSString* message = [command.arguments objectAtIndex:0]; + NSDictionary *attributes = [command.arguments objectAtIndex:1]; + + NSMutableDictionary *mutableDictionary = [attributes mutableCopy]; //Make the dictionary mutable to change/add + + mutableDictionary[@"message"] = message; + + [NewRelic logAll:mutableDictionary]; +} @end diff --git a/www/js/newrelic.js b/www/js/newrelic.js index 392bf1d..de11afa 100644 --- a/www/js/newrelic.js +++ b/www/js/newrelic.js @@ -124,10 +124,27 @@ endInteraction: function (interactionId, cb, fail) { cordova.exec(cb, fail, "NewRelicCordovaPlugin", "endInteraction", [interactionId]); }, - + + /** + * Send a message to the New Relic Mobile agent logs. + * @param type A string that represents the type of the console log. It can be 'error', 'warn', 'log', 'debug', or 'assert'. + * @param args An array of arguments that are passed to the console log. + */ sendConsole(type, args) { const argsStr = JSON.stringify(args, getCircularReplacer()); this.send('MobileJSConsole', { consoleType: type, args: argsStr }); + + if(type === 'error') { + this.logError(argsStr); + } else if(type === 'warn') { + this.logWarn(argsStr); + } else if(type === 'log') { + this.logInfo(argsStr); + } else if(type === 'debug') { + this.logDebug(argsStr); + } else if(type === 'assert') { + this.logVerbose(argsStr); + } }, send(name, args) { @@ -347,6 +364,110 @@ }); }, + /** + * Logs an informational message using the NewRelicCordovaPlugin. + * + * @param {string} message - The message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logInfo method. + * @param {function} fail - The callback function to be executed if the logInfo method fails. + */ + logInfo: function (message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logInfo", [message]); + }, + + + /** + * Logs an error message using the NewRelicCordovaPlugin. + * + * @param {string} message - The error message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logError method. + * @param {function} fail - The callback function to be executed if the logError method fails. + */ + logError: function (message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logError", [message]); + }, + + /** + * Logs a warning message using the NewRelicCordovaPlugin. + * + * @param {string} message - The warning message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logWarn method. + * @param {function} fail - The callback function to be executed if the logWarn method fails. + */ + logWarn: function (message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logWarn", [message]); + }, + + /** + * Logs a debug message using the NewRelicCordovaPlugin. + * + * @param {string} message - The debug message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logDebug method. + * @param {function} fail - The callback function to be executed if the logDebug method fails. + */ + logDebug: function (message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logDebug", [message]); + }, + + /** + * Logs a verbose message using the NewRelicCordovaPlugin. + * + * @param {string} message - The verbose message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logVerbose method. + * @param {function} fail - The callback function to be executed if the logVerbose method fails. + */ + logVerbose: function (message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logVerbose", [message]); + }, + + /** + * Logs a message with a specified log level using the NewRelicCordovaPlugin. + * + * @param {string} logLevel - The log level of the message to be logged. + * @param {string} message - The message to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the log method. + * @param {function} fail - The callback function to be executed if the log method fails. + */ + log:function (logLevel, message, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "log", [logLevel, message]); + }, + + /** + * Logs attributes using the NewRelicCordovaPlugin. + * + * @param {Map} attributes - The attributes to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logAttributes method. + * @param {function} fail - The callback function to be executed if the logAttributes method fails. + */ + logAttributes: function (attributes, cb, fail) { + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logAttributes", [attributes]); + }, + + /** + * Logs all attributes using the NewRelicCordovaPlugin. + * + * @param {Error} err The error to record. + * * @param {Map} attributes - The attributes to be logged. + * @param {function} cb - The callback function to be executed upon successful execution of the logAll method. + * @param {function} fail - The callback function to be executed if the logAll method fails. + */ + logAll:function (err,attributes = {}, cb, fail) { + if (attributes === null) { + attributes = {}; + } + if (err) { + var error; + + if (err instanceof Error) { + error = err; + } + + if (typeof err === 'string') { + error = new Error(err || ''); + } + } + cordova.exec(cb, fail, "NewRelicCordovaPlugin", "logAll", [error.message,attributes]); + } } networkRequest = {}; @@ -557,7 +678,11 @@ const defaultLog = window.console.log; const defaultWarn = window.console.warn; const defaultError = window.console.error; - + const defaultDebug = window.console.debug; + const defaultAssert = window.console.assert; + + + console.log = function () { NewRelic.sendConsole('log', arguments); defaultLog.apply(console, arguments); @@ -570,6 +695,16 @@ NewRelic.sendConsole('error', arguments); defaultError.apply(console, arguments); }; + + console.debug = function () { + NewRelic.sendConsole('debug', arguments); + defaultDebug.apply(console, arguments); + }; + + console.assert = function () { + NewRelic.sendConsole('assert', arguments); + defaultAssert.apply(console, arguments); + }; class Utils { static isObject(value) {