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.
@@ -0,0 +1,291 @@
1
+ import Foundation
2
+ import UIKit
3
+
4
+ @objc(UnviredLogger) class UnviredLogger : CDVPlugin {
5
+
6
+ private let LOG_FOLDER_NAME = "AppLogs"
7
+ private let LOG_FILE_NAME = "log.txt"
8
+ private let BACKUP_LOG_FILE_NAME = "log_backup.txt"
9
+ private let MAX_LOG_SIZE: Int64 = 5 * 1024 * 1024 // 5MB
10
+
11
+ private var defaultLogLevel: String = "info"
12
+
13
+ @objc(logDebug:)
14
+ func logDebug(_ command: CDVInvokedUrlCommand) {
15
+ loggerWithLevel(command)
16
+ }
17
+
18
+ @objc(logInfo:)
19
+ func logInfo(_ command: CDVInvokedUrlCommand) {
20
+ loggerWithLevel(command)
21
+ }
22
+
23
+ @objc(logError:)
24
+ func logError(_ command: CDVInvokedUrlCommand) {
25
+ loggerWithLevel(command)
26
+ }
27
+
28
+ @objc(loggerWithLevel:)
29
+ func loggerWithLevel(_ command: CDVInvokedUrlCommand) {
30
+ guard let args = command.arguments.first as? [String: Any] else {
31
+ sendErrorResult(command.callbackId, message: "Invalid arguments")
32
+ return
33
+ }
34
+
35
+ guard let userId = args["userId"] as? String, !userId.isEmpty else {
36
+ sendErrorResult(command.callbackId, message: "userId is required")
37
+ return
38
+ }
39
+
40
+ guard let level = args["level"] as? String, !level.isEmpty else {
41
+ sendErrorResult(command.callbackId, message: "level is required")
42
+ return
43
+ }
44
+
45
+ guard let message = args["message"] as? String, !message.isEmpty else {
46
+ sendErrorResult(command.callbackId, message: "message is required")
47
+ return
48
+ }
49
+
50
+ let sourceClass = args["sourceClass"] as? String ?? ""
51
+ let sourceMethod = args["sourceMethod"] as? String ?? ""
52
+
53
+ // Log level filtering
54
+ if shouldSkipLog(level: level) {
55
+ sendSuccessResult(command.callbackId, message: "Log skipped due to level filter")
56
+ return
57
+ }
58
+
59
+ do {
60
+ let logFile = try getLogFile(userId: userId)
61
+ try checkAndRotateLogFile(logFile: logFile, userId: userId)
62
+
63
+ let logEntry = formatLogEntry(level: level, sourceClass: sourceClass, sourceMethod: sourceMethod, message: message)
64
+ try appendToFile(file: logFile, data: logEntry)
65
+
66
+ sendSuccessResult(command.callbackId, message: "Logged to \(logFile.path)")
67
+ } catch {
68
+ sendErrorResult(command.callbackId, message: "Logging failed: \(error.localizedDescription)")
69
+ }
70
+ }
71
+
72
+ @objc(setLogLevel:)
73
+ func setLogLevel(_ command: CDVInvokedUrlCommand) {
74
+ guard let args = command.arguments.first as? [String: Any],
75
+ let level = args["level"] as? String else {
76
+ sendErrorResult(command.callbackId, message: "Invalid log level")
77
+ return
78
+ }
79
+
80
+ defaultLogLevel = level
81
+ sendSuccessResult(command.callbackId, message: "Log level set to \(level)")
82
+ }
83
+
84
+ @objc(getLogLevel:)
85
+ func getLogLevel(_ command: CDVInvokedUrlCommand) {
86
+ sendSuccessResult(command.callbackId, message: defaultLogLevel)
87
+ }
88
+
89
+ @objc(getLogFileContent:)
90
+ func getLogFileContent(_ command: CDVInvokedUrlCommand) {
91
+ guard let args = command.arguments.first as? [String: Any],
92
+ let userId = args["userId"] as? String else {
93
+ sendErrorResult(command.callbackId, message: "userId is required")
94
+ return
95
+ }
96
+
97
+ do {
98
+ let logFile = try getLogFile(userId: userId)
99
+ let content = try readFile(file: logFile)
100
+ sendSuccessResult(command.callbackId, message: content)
101
+ } catch {
102
+ sendErrorResult(command.callbackId, message: "Failed to read log file: \(error.localizedDescription)")
103
+ }
104
+ }
105
+
106
+ @objc(clearLogFile:)
107
+ func clearLogFile(_ command: CDVInvokedUrlCommand) {
108
+ guard let args = command.arguments.first as? [String: Any],
109
+ let userId = args["userId"] as? String else {
110
+ sendErrorResult(command.callbackId, message: "userId is required")
111
+ return
112
+ }
113
+
114
+ do {
115
+ let logFile = try getLogFile(userId: userId)
116
+ try "".write(to: logFile, atomically: true, encoding: .utf8)
117
+ sendSuccessResult(command.callbackId, message: "Log file cleared")
118
+ } catch {
119
+ sendErrorResult(command.callbackId, message: "Failed to clear log file: \(error.localizedDescription)")
120
+ }
121
+ }
122
+
123
+ @objc(getBackupLogFileContent:)
124
+ func getBackupLogFileContent(_ command: CDVInvokedUrlCommand) {
125
+ guard let args = command.arguments.first as? [String: Any],
126
+ let userId = args["userId"] as? String else {
127
+ sendErrorResult(command.callbackId, message: "userId is required")
128
+ return
129
+ }
130
+
131
+ do {
132
+ let backupFile = try getBackupLogFile(userId: userId)
133
+ let content = try readFile(file: backupFile)
134
+ sendSuccessResult(command.callbackId, message: content)
135
+ } catch {
136
+ sendErrorResult(command.callbackId, message: "Failed to read backup log file: \(error.localizedDescription)")
137
+ }
138
+ }
139
+
140
+ @objc(copyLogToBackup:)
141
+ func copyLogToBackup(_ command: CDVInvokedUrlCommand) {
142
+ guard let args = command.arguments.first as? [String: Any],
143
+ let userId = args["userId"] as? String else {
144
+ sendErrorResult(command.callbackId, message: "userId is required")
145
+ return
146
+ }
147
+
148
+ do {
149
+ let logFile = try getLogFile(userId: userId)
150
+ let backupFile = try getBackupLogFile(userId: userId)
151
+ try copyFile(from: logFile, to: backupFile)
152
+ sendSuccessResult(command.callbackId, message: "Log file copied to backup")
153
+ } catch {
154
+ sendErrorResult(command.callbackId, message: "Failed to copy log file to backup: \(error.localizedDescription)")
155
+ }
156
+ }
157
+
158
+ @objc(getLogFileURL:)
159
+ func getLogFileURL(_ command: CDVInvokedUrlCommand) {
160
+ guard let args = command.arguments.first as? [String: Any],
161
+ let userId = args["userId"] as? String else {
162
+ sendErrorResult(command.callbackId, message: "userId is required")
163
+ return
164
+ }
165
+
166
+ do {
167
+ let logFile = try getLogFile(userId: userId)
168
+ sendSuccessResult(command.callbackId, message: logFile.path)
169
+ } catch {
170
+ sendErrorResult(command.callbackId, message: "Failed to get log file URL: \(error.localizedDescription)")
171
+ }
172
+ }
173
+
174
+ @objc(getBackupLogFileURL:)
175
+ func getBackupLogFileURL(_ command: CDVInvokedUrlCommand) {
176
+ guard let args = command.arguments.first as? [String: Any],
177
+ let userId = args["userId"] as? String else {
178
+ sendErrorResult(command.callbackId, message: "userId is required")
179
+ return
180
+ }
181
+
182
+ do {
183
+ let backupFile = try getBackupLogFile(userId: userId)
184
+ sendSuccessResult(command.callbackId, message: backupFile.path)
185
+ } catch {
186
+ sendErrorResult(command.callbackId, message: "Failed to get backup log file URL: \(error.localizedDescription)")
187
+ }
188
+ }
189
+
190
+ // MARK: - Helper Methods
191
+
192
+ private func shouldSkipLog(level: String) -> Bool {
193
+ let normLevel = level.lowercased()
194
+ let normDefault = defaultLogLevel.lowercased()
195
+
196
+ if normDefault == "error" && (normLevel == "debug" || normLevel == "info") {
197
+ return true
198
+ }
199
+ if normDefault == "info" && normLevel == "debug" {
200
+ return true
201
+ }
202
+ return false
203
+ }
204
+
205
+ private func getLogFile(userId: String) throws -> URL {
206
+ let userDir = try getUserLogDir(userId: userId)
207
+ return userDir.appendingPathComponent(LOG_FILE_NAME)
208
+ }
209
+
210
+ private func getBackupLogFile(userId: String) throws -> URL {
211
+ let userDir = try getUserLogDir(userId: userId)
212
+ return userDir.appendingPathComponent(BACKUP_LOG_FILE_NAME)
213
+ }
214
+
215
+ private func getUserLogDir(userId: String) throws -> URL {
216
+ let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
217
+ let userDir = documentsPath.appendingPathComponent(userId).appendingPathComponent(LOG_FOLDER_NAME)
218
+
219
+ if !FileManager.default.fileExists(atPath: userDir.path) {
220
+ try FileManager.default.createDirectory(at: userDir, withIntermediateDirectories: true, attributes: nil)
221
+ }
222
+
223
+ return userDir
224
+ }
225
+
226
+ private func checkAndRotateLogFile(logFile: URL, userId: String) throws {
227
+ if FileManager.default.fileExists(atPath: logFile.path) {
228
+ let attributes = try FileManager.default.attributesOfItem(atPath: logFile.path)
229
+ if let fileSize = attributes[.size] as? Int64, fileSize > MAX_LOG_SIZE {
230
+ let backupFile = try getBackupLogFile(userId: userId)
231
+ try copyFile(from: logFile, to: backupFile)
232
+ try "".write(to: logFile, atomically: true, encoding: .utf8)
233
+ }
234
+ }
235
+ }
236
+
237
+ private func formatLogEntry(level: String, sourceClass: String, sourceMethod: String, message: String) -> String {
238
+ let dateFormatter = DateFormatter()
239
+ dateFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss"
240
+ dateFormatter.locale = Locale.current
241
+ let localDate = dateFormatter.string(from: Date())
242
+
243
+ let utcFormatter = DateFormatter()
244
+ utcFormatter.dateFormat = "dd-MM-yyyy HH:mm:ss"
245
+ utcFormatter.timeZone = TimeZone(abbreviation: "UTC")
246
+ let utcDate = utcFormatter.string(from: Date())
247
+
248
+ let prefix = level.lowercased() == "error" ? "⭕️⭕️⭕️ " : ""
249
+ return "\(prefix)\(localDate) | UTC:\(utcDate) | \(getStringFromLevel(level: level)) | \(sourceClass) | \(sourceMethod) | \(message)\n"
250
+ }
251
+
252
+ private func getStringFromLevel(level: String) -> String {
253
+ switch level.lowercased() {
254
+ case "info": return "IMPORTANT"
255
+ case "error": return "ERROR"
256
+ case "debug": return "DEBUG"
257
+ default: return ""
258
+ }
259
+ }
260
+
261
+ private func appendToFile(file: URL, data: String) throws {
262
+ let fileHandle = try FileHandle(forWritingTo: file)
263
+ fileHandle.seekToEndOfFile()
264
+ fileHandle.write(data.data(using: .utf8)!)
265
+ fileHandle.closeFile()
266
+ }
267
+
268
+ private func readFile(file: URL) throws -> String {
269
+ if !FileManager.default.fileExists(atPath: file.path) {
270
+ return ""
271
+ }
272
+ return try String(contentsOf: file, encoding: .utf8)
273
+ }
274
+
275
+ private func copyFile(from: URL, to: URL) throws {
276
+ if !FileManager.default.fileExists(atPath: from.path) {
277
+ return
278
+ }
279
+ try FileManager.default.copyItem(at: from, to: to)
280
+ }
281
+
282
+ private func sendSuccessResult(_ callbackId: String, message: String) {
283
+ let result = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: message)
284
+ self.commandDelegate.send(result, callbackId: callbackId)
285
+ }
286
+
287
+ private func sendErrorResult(_ callbackId: String, message: String) {
288
+ let result = CDVPluginResult(status: CDVCommandStatus_ERROR, messageAs: message)
289
+ self.commandDelegate.send(result, callbackId: callbackId)
290
+ }
291
+ }
package/www/logger.js ADDED
@@ -0,0 +1,174 @@
1
+ var exec = require('cordova/exec');
2
+
3
+ // LogLevel constants for use in Cordova apps
4
+ exports.LogLevel = {
5
+ Debug: 'debug',
6
+ Error: 'error',
7
+ Info: 'info'
8
+ };
9
+
10
+ /**
11
+ * Log a message with a specific level
12
+ * @param {string} userId - The user ID
13
+ * @param {string} level - The log level ('debug', 'info', 'error')
14
+ * @param {string} sourceClass - The class name (optional)
15
+ * @param {string} sourceMethod - The method name (optional)
16
+ * @param {string} message - The message to log
17
+ * @param {function} success - Success callback
18
+ * @param {function} error - Error callback
19
+ */
20
+
21
+ exports.loggerWithLevel = function (userId, level, sourceClass, sourceMethod, message, success, error) {
22
+ if (!userId) {
23
+ if (error) error('User ID is required');
24
+ return;
25
+ }
26
+ exec(success, error, 'UnviredLogger', 'loggerWithLevel', [{ userId: userId, level: level, sourceClass: sourceClass, sourceMethod: sourceMethod, message: message }]);
27
+ };
28
+
29
+ /**
30
+ * Set the log level for filtering messages
31
+ * @param {string} level - The log level ('debug', 'info', 'error')
32
+ * @param {function} success - Success callback
33
+ * @param {function} error - Error callback
34
+ */
35
+ exports.setLogLevel = function (level, success, error) {
36
+ if (!level) {
37
+ if (error) error('Log level is required');
38
+ return;
39
+ }
40
+ exec(success, error, 'UnviredLogger', 'setLogLevel', [level]);
41
+ };
42
+
43
+ /**
44
+ * Get the content of the log file for a specific user
45
+ * @param {string} userId - The user ID
46
+ * @param {function} success - Success callback (receives log content as string)
47
+ * @param {function} error - Error callback
48
+ */
49
+ exports.getLogFileContent = function (userId, success, error) {
50
+ if (!userId) {
51
+ if (error) error('User ID is required');
52
+ return;
53
+ }
54
+ exec(success, error, 'UnviredLogger', 'getLogFileContent', [{ userId: userId }]);
55
+ };
56
+
57
+ /**
58
+ * Clear the log file for a specific user
59
+ * @param {string} userId - The user ID
60
+ * @param {function} success - Success callback
61
+ * @param {function} error - Error callback
62
+ */
63
+ exports.clearLogFile = function (userId, success, error) {
64
+ if (!userId) {
65
+ if (error) error('User ID is required');
66
+ return;
67
+ }
68
+ exec(success, error, 'UnviredLogger', 'clearLogFile', [{ userId: userId }]);
69
+ };
70
+
71
+ /**
72
+ * Get the content of the backup log file for a specific user
73
+ * @param {string} userId - The user ID
74
+ * @param {function} success - Success callback (receives backup log content as string)
75
+ * @param {function} error - Error callback
76
+ */
77
+ exports.getBackupLogFileContent = function (userId, success, error) {
78
+ if (!userId) {
79
+ if (error) error('User ID is required');
80
+ return;
81
+ }
82
+ exec(success, error, 'UnviredLogger', 'getBackupLogFileContent', [{ userId: userId }]);
83
+ };
84
+
85
+ /**
86
+ * Copy the log file to backup for a specific user
87
+ * @param {string} userId - The user ID
88
+ * @param {function} success - Success callback
89
+ * @param {function} error - Error callback
90
+ */
91
+ exports.copyLogToBackup = function (userId, success, error) {
92
+ if (!userId) {
93
+ if (error) error('User ID is required');
94
+ return;
95
+ }
96
+ exec(success, error, 'UnviredLogger', 'copyLogToBackup', [{ userId: userId }]);
97
+ };
98
+
99
+ /**
100
+ * Convenience methods for different log levels
101
+ */
102
+ exports.logDebug = function (userId, sourceClass, sourceMethod, message, success, error) {
103
+ if (!userId) {
104
+ if (error) error('User ID is required');
105
+ return;
106
+ }
107
+ if (!message) {
108
+ if (error) error('Message is required');
109
+ return;
110
+ }
111
+ exec(success, error, 'UnviredLogger', 'logDebug', [{
112
+ userId: userId,
113
+ level: exports.LogLevel.Debug,
114
+ message: message,
115
+ sourceClass: sourceClass,
116
+ sourceMethod: sourceMethod
117
+ }]);
118
+ };
119
+
120
+ exports.logInfo = function (userId, sourceClass, sourceMethod, message, success, error) {
121
+ if (!userId) {
122
+ if (error) error('User ID is required');
123
+ return;
124
+ }
125
+ if (!message) {
126
+ if (error) error('Message is required');
127
+ return;
128
+ }
129
+ exec(success, error, 'UnviredLogger', 'logInfo', [{
130
+ userId: userId,
131
+ level: exports.LogLevel.Info,
132
+ message: message,
133
+ sourceClass: sourceClass,
134
+ sourceMethod: sourceMethod
135
+ }]);
136
+ };
137
+
138
+ exports.logError = function (userId, sourceClass, sourceMethod, message, success, error) {
139
+ if (!userId) {
140
+ if (error) error('User ID is required');
141
+ return;
142
+ }
143
+ if (!message) {
144
+ if (error) error('Message is required');
145
+ return;
146
+ }
147
+ exec(success, error, 'UnviredLogger', 'logError', [{
148
+ userId: userId,
149
+ level: exports.LogLevel.Error,
150
+ message: message,
151
+ sourceClass: sourceClass,
152
+ sourceMethod: sourceMethod
153
+ }]);
154
+ };
155
+
156
+ exports.getLogFileURL = function (userId, success, error) {
157
+ if (!userId) {
158
+ if (error) error('User ID is required');
159
+ return;
160
+ }
161
+ exec(success, error, 'UnviredLogger', 'getLogFileURL', [{ userId: userId }]);
162
+ };
163
+
164
+ exports.getBackupLogFileURL = function (userId, success, error) {
165
+ if (!userId) {
166
+ if (error) error('User ID is required');
167
+ return;
168
+ }
169
+ exec(success, error, 'UnviredLogger', 'getBackupLogFileURL', [{ userId: userId }]);
170
+ };
171
+
172
+ exports.getLogLevel = function (success, error) {
173
+ exec(success, error, 'UnviredLogger', 'getLogLevel', []);
174
+ };