cordova-plugin-unvired-logger 0.0.1

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/README.md ADDED
@@ -0,0 +1,272 @@
1
+ # Cordova Plugin Unvired Logger
2
+
3
+ A comprehensive Cordova plugin that provides advanced logging functionality with log levels, file management, and user-specific log organization. Supports Android, iOS, Electron, and Browser platforms.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ cordova plugin add cordova-plugin-unvired-logger
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Basic Logging
14
+
15
+ ```javascript
16
+ // Info log
17
+ Logger.logInfo("user123", "AuthService", "login", "User login successful",
18
+ function(success) {
19
+ console.log("Log saved:", success);
20
+ },
21
+ function(error) {
22
+ console.error("Logging failed:", error);
23
+ }
24
+ );
25
+
26
+ // Debug log
27
+ Logger.logDebug("user123", "UserService", "getUserData", "Fetching user data from API",
28
+ function(success) {
29
+ console.log("Debug log saved:", success);
30
+ },
31
+ function(error) {
32
+ console.error("Debug logging failed:", error);
33
+ }
34
+ );
35
+
36
+ // Error log
37
+ Logger.logError("user123", "UserService", "getUserData", "Failed to fetch user data: Network error",
38
+ function(success) {
39
+ console.log("Error log saved:", success);
40
+ },
41
+ function(error) {
42
+ console.error("Error logging failed:", error);
43
+ }
44
+ );
45
+ ```
46
+
47
+ ### Advanced Logging with Level
48
+
49
+ ```javascript
50
+ Logger.loggerWithLevel("user123", "debug", "MyClass", "myMethod", "This is a debug message",
51
+ function(success) {
52
+ console.log("Log saved:", success);
53
+ },
54
+ function(error) {
55
+ console.error("Logging failed:", error);
56
+ }
57
+ );
58
+ ```
59
+
60
+ ### Log Level Management
61
+
62
+ ```javascript
63
+ // Set log level to control which messages are logged
64
+ Logger.setLogLevel("debug", // Logs all levels
65
+ function(success) {
66
+ console.log("Log level set to Debug");
67
+ },
68
+ function(error) {
69
+ console.error("Failed to set log level:", error);
70
+ }
71
+ );
72
+
73
+ Logger.setLogLevel("info", // Logs Info and Error only
74
+ function(success) {
75
+ console.log("Log level set to Info");
76
+ },
77
+ function(error) {
78
+ console.error("Failed to set log level:", error);
79
+ }
80
+ );
81
+
82
+ Logger.setLogLevel("error", // Logs Error only
83
+ function(success) {
84
+ console.log("Log level set to Error");
85
+ },
86
+ function(error) {
87
+ console.error("Failed to set log level:", error);
88
+ }
89
+ );
90
+ ```
91
+
92
+ ### Log File Management
93
+
94
+ ```javascript
95
+ // Get log file content
96
+ Logger.getLogFileContent("user123",
97
+ function(content) {
98
+ console.log("Log file content:", content);
99
+ },
100
+ function(error) {
101
+ console.error("Failed to read log file:", error);
102
+ }
103
+ );
104
+
105
+ // Clear log file
106
+ Logger.clearLogFile("user123",
107
+ function(success) {
108
+ console.log("Log file cleared successfully");
109
+ },
110
+ function(error) {
111
+ console.error("Failed to clear log file:", error);
112
+ }
113
+ );
114
+
115
+ // Get backup log file content (when log rotation occurs)
116
+ Logger.getBackupLogFileContent("user123",
117
+ function(content) {
118
+ console.log("Backup log file content:", content);
119
+ },
120
+ function(error) {
121
+ console.error("Failed to read backup log file:", error);
122
+ }
123
+ );
124
+ ```
125
+
126
+ ### Complete Test Example
127
+
128
+ ```javascript
129
+ function testLogger() {
130
+ if (window && Logger) {
131
+ console.log("Testing UnviredLogger plugin...");
132
+
133
+ // Test basic logging
134
+ Logger.logInfo("testuser", "AuthService", "login", "User login successful",
135
+ function(success) {
136
+ console.log("Basic log success:", success);
137
+
138
+ // Test log level setting
139
+ Logger.setLogLevel("debug",
140
+ function() {
141
+ console.log("Log level set to Debug");
142
+
143
+ // Test convenience methods
144
+ Logger.logDebug("testuser", "TestClass", "testMethod", "Debug message test",
145
+ function() {
146
+ console.log("Debug log successful");
147
+
148
+ // Test reading log content
149
+ Logger.getLogFileContent("testuser",
150
+ function(content) {
151
+ console.log("Log file content:", content);
152
+ },
153
+ function(error) {
154
+ console.error("Failed to read log:", error);
155
+ }
156
+ );
157
+ },
158
+ function(error) {
159
+ console.error("Debug log failed:", error);
160
+ }
161
+ );
162
+ },
163
+ function(error) {
164
+ console.error("Failed to set log level:", error);
165
+ }
166
+ );
167
+ },
168
+ function(error) {
169
+ console.error("Basic log failed:", error);
170
+ }
171
+ );
172
+ } else {
173
+ console.warn("UnviredLogger not available.");
174
+ }
175
+ }
176
+
177
+ // Call the test function
178
+ testLogger();
179
+ ```
180
+
181
+ ## Supported Platforms
182
+
183
+ - **Android**: Native Java implementation with file system access
184
+ - **iOS**: Native Swift implementation with file system access
185
+ - **Electron**: Node.js implementation with file system access
186
+ - **Browser**: JavaScript implementation using localStorage
187
+
188
+ ## Features
189
+
190
+ - **Advanced logging**: Log messages with class, method, and log level information
191
+ - **Log levels**: Debug, Info, and Error levels with filtering
192
+ - **User-specific logging**: Logs are organized by user ID
193
+ - **Automatic file creation**: Log files and directories are created automatically
194
+ - **Log rotation**: Automatic backup when log file exceeds 5MB
195
+ - **Timestamped entries**: Each log entry includes local and UTC timestamps
196
+ - **File management**: Read, clear, and backup log files
197
+ - **Cross-platform**: Consistent API across all supported platforms
198
+ - **Convenience methods**: Easy-to-use methods for different log levels
199
+
200
+ ## Platform-Specific Details
201
+
202
+ ### Android
203
+ - Logs are stored in the app's internal storage: `/data/data/[package]/files/[userId]/AppLogs/`
204
+ - Requires storage permissions for external storage access
205
+ - Automatic log rotation when file size exceeds 5MB
206
+
207
+ ### iOS
208
+ - Logs are stored in the app's Documents directory: `Documents/[userId]/AppLogs/`
209
+ - Uses native Swift implementation for optimal performance
210
+ - Automatic log rotation when file size exceeds 5MB
211
+
212
+ ### Electron
213
+ - Logs are stored in the app's user data directory: `[userData]/[userId]/log/`
214
+ - Uses Node.js file system APIs
215
+ - Automatic log rotation when file size exceeds 5MB
216
+
217
+ ### Browser
218
+ - Logs are stored in browser's localStorage with keys: `unvired_logger_[userId]_log.txt`
219
+ - Fallback implementation when Cordova is not available
220
+ - Automatic content truncation when size exceeds 5MB
221
+ - Console logging for debugging purposes
222
+
223
+ ## Log Levels
224
+
225
+ - **Debug**: Detailed information for debugging (only logged when level is set to Debug)
226
+ - **Info**: General information about application flow (logged when level is Info or Debug)
227
+ - **Error**: Error messages and exceptions (always logged)
228
+
229
+ ## File Structure
230
+
231
+ Logs are stored in the following structure:
232
+ ```
233
+ {userDataPath}/{userId}/AppLogs/log.txt
234
+ {userDataPath}/{userId}/AppLogs/log_backup.txt
235
+ ```
236
+
237
+ Where:
238
+ - `userDataPath` is the Electron app's user data directory
239
+ - `userId` is the user identifier you provide
240
+ - `AppLogs` is the log folder name
241
+ - `log.txt` is the current log file
242
+ - `log_backup.txt` is the backup file (created during rotation)
243
+
244
+ ## API Reference
245
+
246
+ ### Core Methods
247
+ - `log(userId, message, sourceClass?, sourceMethod?, level?, success, error)` - Log a message
248
+ - `setLogLevel(level, success, error)` - Set the logging level
249
+ - `getLogFileContent(userId, success, error)` - Get log file content
250
+ - `clearLogFile(userId, success, error)` - Clear the log file
251
+ - `getBackupLogFileContent(userId, success, error)` - Get backup log file content
252
+
253
+ ### Convenience Methods
254
+ - `logDebug(userId, sourceClass, sourceMethod, message, success, error)` - Log debug message
255
+ - `logInfo(userId, sourceClass, sourceMethod, message, success, error)` - Log info message
256
+ - `logError(userId, sourceClass, sourceMethod, message, success, error)` - Log error message
257
+
258
+ ### Constants
259
+ - `UnviredLogger.LogLevel.Debug` - Debug log level
260
+ - `UnviredLogger.LogLevel.Info` - Info log level
261
+ - `UnviredLogger.LogLevel.Error` - Error log level
262
+
263
+ ## Requirements
264
+
265
+ - Cordova 9.0.0 or higher
266
+ - cordova-electron 1.0.0 or higher
267
+ - Electron 20.0.0 or higher
268
+ - Node.js 14.0.0 or higher
269
+
270
+ ## License
271
+
272
+ MIT
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "cordova-plugin-unvired-logger",
3
+ "version": "0.0.1",
4
+ "description": "A logger plugin for Electron, Android, Browser, and iOS that appends logs to log.txt files organized by user ID.",
5
+ "cordova": {
6
+ "id": "cordova-plugin-unvired-logger",
7
+ "platforms": [
8
+ "electron",
9
+ "android",
10
+ "browser",
11
+ "ios"
12
+ ]
13
+ },
14
+ "keywords": [
15
+ "cordova",
16
+ "electron",
17
+ "android",
18
+ "plugin",
19
+ "logger"
20
+ ],
21
+ "author": "Unvired Inc.",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "fs": "^0.0.1-security"
25
+ }
26
+ }
package/plugin.xml ADDED
@@ -0,0 +1,49 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <plugin id="cordova-plugin-unvired-logger" version="0.0.1"
3
+ xmlns="http://apache.org/cordova/ns/plugins/1.0"
4
+ xmlns:android="http://schemas.android.com/apk/res/android">
5
+
6
+ <name>UnviredLogger</name>
7
+ <description>A logger plugin for Android, iOS, Electron, and Browser that appends logs to log.txt files organized by user ID.</description>
8
+
9
+ <js-module src="www/logger.js" name="UnviredLogger">
10
+ <clobbers target="Logger" />
11
+ </js-module>
12
+
13
+ <platform name="electron">
14
+ <framework src="src/electron"/>
15
+ </platform>
16
+
17
+ <platform name="android">
18
+ <config-file target="res/xml/config.xml" parent="/*">
19
+ <feature name="UnviredLogger">
20
+ <param name="android-package" value="cordova.plugin.unvired.logger.UnviredLogger" />
21
+ </feature>
22
+ </config-file>
23
+
24
+ <source-file src="src/android/UnviredLogger.java" target-dir="src/cordova/plugin/unvired/logger" />
25
+
26
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
27
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
28
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
29
+ </platform>
30
+
31
+ <platform name="ios">
32
+ <config-file target="config.xml" parent="/*">
33
+ <feature name="UnviredLogger">
34
+ <param name="ios-package" value="UnviredLogger" />
35
+ </feature>
36
+ </config-file>
37
+
38
+ <source-file src="src/ios/UnviredLogger.swift" />
39
+
40
+ <framework src="Foundation.framework" />
41
+ <framework src="UIKit.framework" />
42
+ </platform>
43
+
44
+ <platform name="browser">
45
+ <js-module src="src/browser/Logger.js" name="UnviredLoggerBrowser">
46
+ <clobbers target="UnviredLoggerBrowser" />
47
+ </js-module>
48
+ </platform>
49
+ </plugin>
@@ -0,0 +1,265 @@
1
+ package cordova.plugin.unvired.logger;
2
+
3
+ import android.content.Context;
4
+ import android.os.Environment;
5
+
6
+ import org.apache.cordova.CordovaPlugin;
7
+ import org.apache.cordova.CallbackContext;
8
+ import org.json.JSONArray;
9
+ import org.json.JSONException;
10
+ import org.json.JSONObject;
11
+
12
+ import java.io.*;
13
+ import java.text.SimpleDateFormat;
14
+ import java.util.Date;
15
+ import java.util.Locale;
16
+
17
+ public class UnviredLogger extends CordovaPlugin {
18
+
19
+ private static final String LOG_FOLDER_NAME = "AppLogs";
20
+ private static final String LOG_FILE_NAME = "log.txt";
21
+ private static final String BACKUP_LOG_FILE_NAME = "log_backup.txt";
22
+ private static final long MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB
23
+
24
+ private String defaultLogLevel = "info";
25
+
26
+ @Override
27
+ public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
28
+ try {
29
+ switch (action) {
30
+ case "logDebug":
31
+ case "logInfo":
32
+ case "logError":
33
+ case "loggerWithLevel":
34
+ logWithLevel(args, callbackContext);
35
+ return true;
36
+ case "setLogLevel":
37
+ setLogLevel(args, callbackContext);
38
+ return true;
39
+ case "getLogLevel":
40
+ callbackContext.success(defaultLogLevel);
41
+ return true;
42
+ case "getLogFileContent":
43
+ getLogFileContent(args, callbackContext);
44
+ return true;
45
+ case "clearLogFile":
46
+ clearLogFile(args, callbackContext);
47
+ return true;
48
+ case "getBackupLogFileContent":
49
+ getBackupLogFileContent(args, callbackContext);
50
+ return true;
51
+ case "copyLogToBackup":
52
+ copyLogToBackup(args, callbackContext);
53
+ return true;
54
+ case "getLogFileURL":
55
+ getLogFileURL(args, callbackContext);
56
+ return true;
57
+ case "getBackupLogFileURL":
58
+ getBackupLogFileURL(args, callbackContext);
59
+ return true;
60
+ default:
61
+ return false;
62
+ }
63
+ } catch (Exception e) {
64
+ callbackContext.error("Error: " + e.getMessage());
65
+ return false;
66
+ }
67
+ }
68
+
69
+ private void setLogLevel(JSONArray args, CallbackContext callbackContext) {
70
+ try {
71
+ String level = args.getString(0);
72
+ defaultLogLevel = level;
73
+ callbackContext.success();
74
+ } catch (Exception e) {
75
+ callbackContext.error("Failed to set log level: " + e.getMessage());
76
+ }
77
+ }
78
+
79
+ private void logWithLevel(JSONArray args, CallbackContext callbackContext) {
80
+ try {
81
+ JSONObject arg = args.getJSONObject(0);
82
+ String userId = arg.optString("userId");
83
+ String level = arg.optString("level");
84
+ String sourceClass = arg.optString("sourceClass", "");
85
+ String sourceMethod = arg.optString("sourceMethod", "");
86
+ String message = arg.optString("message");
87
+
88
+ if (userId.isEmpty() || level.isEmpty() || message.isEmpty()) {
89
+ callbackContext.error("userId, level, and message are required");
90
+ return;
91
+ }
92
+
93
+ // Log level filtering
94
+ if (shouldSkipLog(level)) {
95
+ callbackContext.success();
96
+ return;
97
+ }
98
+
99
+ File logFile = getLogFile(userId);
100
+ checkAndRotateLogFile(logFile, userId);
101
+
102
+ String logEntry = formatLogEntry(level, sourceClass, sourceMethod, message);
103
+ appendToFile(logFile, logEntry);
104
+
105
+ callbackContext.success("Logged to " + logFile.getAbsolutePath());
106
+ } catch (Exception e) {
107
+ callbackContext.error("Logging failed: " + e.getMessage());
108
+ }
109
+ }
110
+
111
+ private boolean shouldSkipLog(String level) {
112
+ String normLevel = level.toLowerCase();
113
+ String normDefault = defaultLogLevel.toLowerCase();
114
+ if (normDefault.equals("error") && (normLevel.equals("debug") || normLevel.equals("info"))) return true;
115
+ if (normDefault.equals("info") && normLevel.equals("debug")) return true;
116
+ return false;
117
+ }
118
+
119
+ private void getLogFileContent(JSONArray args, CallbackContext callbackContext) {
120
+ try {
121
+ JSONObject arg = args.getJSONObject(0);
122
+ String userId = arg.optString("userId");
123
+ File logFile = getLogFile(userId);
124
+ String content = readFile(logFile);
125
+ callbackContext.success(content);
126
+ } catch (Exception e) {
127
+ callbackContext.error("Failed to read log file: " + e.getMessage());
128
+ }
129
+ }
130
+
131
+ private void clearLogFile(JSONArray args, CallbackContext callbackContext) {
132
+ try {
133
+ JSONObject arg = args.getJSONObject(0);
134
+ String userId = arg.optString("userId");
135
+ File logFile = getLogFile(userId);
136
+ new FileOutputStream(logFile).close();
137
+ callbackContext.success();
138
+ } catch (Exception e) {
139
+ callbackContext.error("Failed to clear log file: " + e.getMessage());
140
+ }
141
+ }
142
+
143
+ private void getBackupLogFileContent(JSONArray args, CallbackContext callbackContext) {
144
+ try {
145
+ JSONObject arg = args.getJSONObject(0);
146
+ String userId = arg.optString("userId");
147
+ File backupFile = getBackupLogFile(userId);
148
+ String content = readFile(backupFile);
149
+ callbackContext.success(content);
150
+ } catch (Exception e) {
151
+ callbackContext.error("Failed to read backup log file: " + e.getMessage());
152
+ }
153
+ }
154
+
155
+ private void copyLogToBackup(JSONArray args, CallbackContext callbackContext) {
156
+ try {
157
+ JSONObject arg = args.getJSONObject(0);
158
+ String userId = arg.optString("userId");
159
+ File logFile = getLogFile(userId);
160
+ File backupFile = getBackupLogFile(userId);
161
+ copyFile(logFile, backupFile);
162
+ callbackContext.success();
163
+ } catch (Exception e) {
164
+ callbackContext.error("Failed to copy log file to backup: " + e.getMessage());
165
+ }
166
+ }
167
+
168
+ private void getLogFileURL(JSONArray args, CallbackContext callbackContext) {
169
+ try {
170
+ JSONObject arg = args.getJSONObject(0);
171
+ String userId = arg.optString("userId");
172
+ File logFile = getLogFile(userId);
173
+ callbackContext.success(logFile.getAbsolutePath());
174
+ } catch (Exception e) {
175
+ callbackContext.error("Failed to get log file URL: " + e.getMessage());
176
+ }
177
+ }
178
+
179
+ private void getBackupLogFileURL(JSONArray args, CallbackContext callbackContext) {
180
+ try {
181
+ JSONObject arg = args.getJSONObject(0);
182
+ String userId = arg.optString("userId");
183
+ File backupFile = getBackupLogFile(userId);
184
+ callbackContext.success(backupFile.getAbsolutePath());
185
+ } catch (Exception e) {
186
+ callbackContext.error("Failed to get backup log file URL: " + e.getMessage());
187
+ }
188
+ }
189
+
190
+ // --- Helper methods ---
191
+
192
+ private File getLogFile(String userId) {
193
+ File dir = getUserLogDir(userId);
194
+ if (!dir.exists()) dir.mkdirs();
195
+ return new File(dir, LOG_FILE_NAME);
196
+ }
197
+
198
+ private File getBackupLogFile(String userId) {
199
+ File dir = getUserLogDir(userId);
200
+ if (!dir.exists()) dir.mkdirs();
201
+ return new File(dir, BACKUP_LOG_FILE_NAME);
202
+ }
203
+
204
+ private File getUserLogDir(String userId) {
205
+ Context ctx = cordova.getActivity().getApplicationContext();
206
+ File userDir = new File(ctx.getFilesDir(), userId + File.separator + LOG_FOLDER_NAME);
207
+ if (!userDir.exists()) userDir.mkdirs();
208
+ return userDir;
209
+ }
210
+
211
+ private void checkAndRotateLogFile(File logFile, String userId) throws IOException {
212
+ if (logFile.exists() && logFile.length() > MAX_LOG_SIZE) {
213
+ File backupFile = getBackupLogFile(userId);
214
+ copyFile(logFile, backupFile);
215
+ new FileOutputStream(logFile).close();
216
+ }
217
+ }
218
+
219
+ private String formatLogEntry(String level, String sourceClass, String sourceMethod, String message) {
220
+ SimpleDateFormat localFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.getDefault());
221
+ SimpleDateFormat utcFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.US);
222
+ utcFormat.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
223
+ Date now = new Date();
224
+ String local = localFormat.format(now);
225
+ String utc = utcFormat.format(now);
226
+ String prefix = level.equalsIgnoreCase("error") ? "⭕️⭕️⭕️ " : "";
227
+ return prefix + local + " | UTC:" + utc + " | " + getStringFromLevel(level) + " | " + sourceClass + " | " + sourceMethod + " | " + message + "\n";
228
+ }
229
+
230
+ private String getStringFromLevel(String level) {
231
+ switch (level.toLowerCase()) {
232
+ case "info": return "IMPORTANT";
233
+ case "error": return "ERROR";
234
+ case "debug": return "DEBUG";
235
+ default: return "";
236
+ }
237
+ }
238
+
239
+ private void appendToFile(File file, String data) throws IOException {
240
+ FileWriter fw = new FileWriter(file, true);
241
+ fw.write(data);
242
+ fw.close();
243
+ }
244
+
245
+ private String readFile(File file) throws IOException {
246
+ if (!file.exists()) return "";
247
+ StringBuilder sb = new StringBuilder();
248
+ BufferedReader br = new BufferedReader(new FileReader(file));
249
+ String line;
250
+ while ((line = br.readLine()) != null) sb.append(line).append("\n");
251
+ br.close();
252
+ return sb.toString();
253
+ }
254
+
255
+ private void copyFile(File src, File dest) throws IOException {
256
+ if (!src.exists()) return;
257
+ FileInputStream in = new FileInputStream(src);
258
+ FileOutputStream out = new FileOutputStream(dest);
259
+ byte[] buf = new byte[1024];
260
+ int len;
261
+ while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
262
+ in.close();
263
+ out.close();
264
+ }
265
+ }