-
Notifications
You must be signed in to change notification settings - Fork 83
/
QorumLogs.swift
executable file
·389 lines (317 loc) · 13.8 KB
/
QorumLogs.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
//
// QorumLogs.swift
// Qorum
//
// Created by Goktug Yilmaz on 27/08/15.
// Copyright (c) 2015 Goktug Yilmaz. All rights reserved.
//
import Foundation
#if os(OSX)
import Cocoa
#elseif os(iOS) || os(tvOS)
import UIKit
#endif
/// Debug error level
private let kLogDebug : String = "Debug";
/// Info error level
private let kLogInfo : String = "Info";
/// Warning error level
private let kLogWarning : String = "Warning";
/// Error error level
private let kLogError : String = "Error";
public struct QorumLogs {
/// While enabled QorumOnlineLogs does not work
public static var enabled = false
/// 1 to 4
public static var minimumLogLevelShown = 1
/// Change the array element with another UIColor. 0 is info gray, 5 is purple, rest are log levels
public static var colorsForLogLevels: [QLColor] = [
QLColor(r: 120, g: 120, b: 120),//0
QLColor(r: 0, g: 180, b: 180), //1
QLColor(r: 0, g: 150, b: 0), //2
QLColor(r: 255, g: 190, b: 0), //3
QLColor(r: 255, g: 0, b: 0), //4
QLColor(r: 160, g: 32, b: 240)] //5
/// Change the array element with another ansi color. 0 is info gray, 5 is purple, rest are log levels
public static var ansiColorsForLogLevels: [String] = [
"37m", // 0 (gray)
"34m", // 1 (blue)
"32m", // 2 (green)
"33m", // 3 (yellow)
"31m", // 4 (red)
"35m"] // 5 (magenta)
/// Change the array element with another Emoji or String. 0 replaces gray color, 5 replaces purple, rest replace log levels
public static var emojisForLogLevels: [String] = [
"", //0
"💙", //1
"💚", //2
"💛", //3
"❤️", //4
"💜"] //5
/// Uses emojis instead of colors when this is false
public static var useColors = false
/// Uses ANSI colors instead of colors or emojis when this is true
public static var useAnsiColors = false
//TODO: Show example in documentation
/// Set your function that will get called whenever something new is logged
public static var trackLogFunction: ((String)->())? = nil
private static var showFiles = [String]()
//==========================================================================================================
// MARK: - Public Methods
//==========================================================================================================
/// Ignores all logs from other files
public static func onlyShowTheseFiles(_ fileNames: Any...) {
minimumLogLevelShown = 1
let showFiles = fileNames.map { fileName in
return fileName as? String ?? {
let classString: String = {
let classString = String(describing: type(of: fileName))
return classString.ns.pathExtension
}()
return classString
}()
}
self.showFiles = showFiles
print(ColorLog.colorizeString("QorumLogs: Only Showing: \(showFiles)", colorId: 5))
}
/// Ignores all logs from other files
public static func onlyShowThisFile(_ fileName: Any) {
onlyShowTheseFiles(fileName)
}
/// Test to see if its working
public static func test() {
let oldDebugLevel = minimumLogLevelShown
minimumLogLevelShown = 1
QL1(kLogDebug)
QL2(kLogInfo)
QL3(kLogWarning)
QL4(kLogError)
minimumLogLevelShown = oldDebugLevel
}
//==========================================================================================================
// MARK: - Private Methods
//==========================================================================================================
fileprivate static func shouldPrintLine(level: Int, fileName: String) -> Bool {
if !QorumLogs.enabled {
return false
} else if QorumLogs.minimumLogLevelShown <= level {
return QorumLogs.shouldShowFile(fileName)
} else {
return false
}
}
fileprivate static func shouldShowFile(_ fileName: String) -> Bool {
return QorumLogs.showFiles.isEmpty || QorumLogs.showFiles.contains(fileName)
}
}
/// Debug error level
private let kOnlineLogDebug : String = "1Debug";
/// Info error level
private let kOnlineLogInfo : String = "2Info";
/// Warning error level
private let kOnlineLogWarning : String = "3Warning";
/// Error error level
private let kOnlineLogError : String = "4Error";
public struct QorumOnlineLogs {
private static let appVersion = versionAndBuild()
private static var googleFormLink: String!
private static var googleFormAppVersionField: String!
private static var googleFormUserInfoField: String!
private static var googleFormMethodInfoField: String!
private static var googleFormErrorTextField: String!
/// Online logs does not work while QorumLogs is enabled
public static var enabled = false
/// 1 to 4
public static var minimumLogLevelShown = 1
/// Empty dictionary, add extra info like user id, username here
public static var extraInformation = [String: String]()
//==========================================================================================================
// MARK: - Public Methods
//==========================================================================================================
/// Test to see if its working
public static func test() {
let oldDebugLevel = minimumLogLevelShown
minimumLogLevelShown = 1
QL1(kLogDebug)
QL2(kLogInfo)
QL3(kLogWarning)
QL4(kLogError)
minimumLogLevelShown = oldDebugLevel
}
/// Setup Google Form links
public static func setupOnlineLogs(formLink: String, versionField: String, userInfoField: String, methodInfoField: String, textField: String) {
googleFormLink = formLink
googleFormAppVersionField = versionField
googleFormUserInfoField = userInfoField
googleFormMethodInfoField = methodInfoField
googleFormErrorTextField = textField
}
//==========================================================================================================
// MARK: - Private Methods
//==========================================================================================================
fileprivate static func sendError<T>(classInformation: String, textObject: T, level: String) {
var text = ""
if let stringObject = textObject as? String {
text = stringObject
} else {
let stringObject = String(describing: textObject)
text = stringObject
}
let versionLevel = (appVersion + " - " + level)
let url = URL(string: googleFormLink)
var postData = googleFormAppVersionField + "=" + versionLevel
postData += "&" + googleFormUserInfoField + "=" + extraInformation.description
postData += "&" + googleFormMethodInfoField + "=" + classInformation
postData += "&" + googleFormErrorTextField + "=" + text
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.httpBody = postData.data(using: String.Encoding.utf8)
#if os(OSX)
if kCFCoreFoundationVersionNumber > kCFCoreFoundationVersionNumber10_10 {
Foundation.URLSession.shared.dataTask(with: request).resume()
} else {
NSURLConnection(request: request, delegate: nil)?.start()
}
#elseif os(iOS)
URLSession.shared.dataTask(with: request).resume()
#endif
let printText = "OnlineLogs: \(extraInformation.description) - \(versionLevel) - \(classInformation) - \(text)"
print(" \(ColorLog.colorizeString(printText, colorId: 5))\n", terminator: "")
}
fileprivate static func shouldSendLine(level: Int, fileName: String) -> Bool {
if !QorumOnlineLogs.enabled {
return false
} else if QorumOnlineLogs.minimumLogLevelShown <= level {
return QorumLogs.shouldShowFile(fileName)
} else {
return false
}
}
}
///Detailed logs only used while debugging
public func QL1<T>(_ debug: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
QLManager(debug, file: file, function: function, line: line, level:1)
}
///General information about app state
public func QL2<T>(_ info: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
QLManager(info,file: file,function: function,line: line,level:2)
}
///Indicates possible error
public func QL3<T>(_ warning: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
QLManager(warning,file: file,function: function,line: line,level:3)
}
///An unexpected error occured
public func QL4<T>(_ error: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line) {
QLManager(error,file: file,function: function,line: line,level:4)
}
private func printLog<T>(_ informationPart: String, text: T, level: Int) {
print(" \(ColorLog.colorizeString(informationPart, colorId: 0))", terminator: "")
print(" \(ColorLog.colorizeString(text, colorId: level))\n", terminator: "")
}
///=====
public func QLShortLine(_ file: String = #file, _ function: String = #function, _ line: Int = #line) {
let lineString = "======================================"
QLineManager(lineString, file: file, function: function, line: line)
}
///+++++
public func QLPlusLine(_ file: String = #file, _ function: String = #function, _ line: Int = #line) {
let lineString = "+++++++++++++++++++++++++++++++++++++"
QLineManager(lineString, file: file, function: function, line: line)
}
///Print data with level
private func QLManager<T>(_ debug: T, file: String, function: String, line: Int, level : Int) {
let levelText : String;
switch (level) {
case 1: levelText = kOnlineLogDebug
case 2: levelText = kOnlineLogInfo
case 3: levelText = kOnlineLogWarning
case 4: levelText = kOnlineLogError
default: levelText = kOnlineLogDebug
}
let fileExtension = file.ns.lastPathComponent.ns.pathExtension
let filename = file.ns.lastPathComponent.ns.deletingPathExtension
var text = ""
if let stringObject = debug as? String {
text = stringObject
} else {
let stringObject = String(describing: debug)
text = stringObject
}
QorumLogs.trackLogFunction?(text)
if QorumLogs.shouldPrintLine(level: level, fileName: filename) {
let informationPart: String
informationPart = "\(filename).\(fileExtension):\(line) \(function):"
printLog(informationPart, text: debug, level: level)
} else if QorumOnlineLogs.shouldSendLine(level: level, fileName: filename) {
let informationPart = "\(filename).\(function)[\(line)]"
QorumOnlineLogs.sendError(classInformation: informationPart, textObject: debug, level: levelText)
}
}
///Print line
private func QLineManager(_ lineString : String, file: String, function: String, line: Int) {
let fileExtension = file.ns.lastPathComponent.ns.pathExtension
let filename = file.ns.lastPathComponent.ns.deletingPathExtension
if QorumLogs.shouldPrintLine(level: 2, fileName: filename) {
let informationPart: String
informationPart = "\(filename).\(fileExtension):\(line) \(function):"
printLog(informationPart, text: lineString, level: 5)
}
}
private struct ColorLog {
private static let ESCAPE = "\u{001b}["
private static let RESET_FG = ESCAPE + "fg;" // Clear any foreground color
private static let RESET_BG = ESCAPE + "bg;" // Clear any background color
private static let RESET = ESCAPE + ";" // Clear any foreground or background color
static func colorizeString<T>(_ object: T, colorId: Int) -> String {
if QorumLogs.useAnsiColors {
return "\(ESCAPE)1m\(ESCAPE)\(QorumLogs.ansiColorsForLogLevels[colorId])\(object)"
} else if QorumLogs.useColors {
return "\(ESCAPE)fg\(QorumLogs.colorsForLogLevels[colorId].redColor),\(QorumLogs.colorsForLogLevels[colorId].greenColor),\(QorumLogs.colorsForLogLevels[colorId].blueColor);\(object)\(RESET)"
} else {
return "\(QorumLogs.emojisForLogLevels[colorId])\(object)\(QorumLogs.emojisForLogLevels[colorId])"
}
}
}
private func versionAndBuild() -> String {
let version = Bundle.main.infoDictionary? ["CFBundleShortVersionString"] as! String
let build = Bundle.main.infoDictionary? [kCFBundleVersionKey as String] as! String
return version == build ? "v\(version)" : "v\(version)(\(build))"
}
private extension String {
/// Qorum Extension
var ns: NSString { return self as NSString }
}
///Used in color settings for QorumLogs
open class QLColor {
#if os(OSX)
var color: NSColor
#elseif os(iOS) || os(tvOS)
var color: UIColor
#endif
public init(r: CGFloat, g: CGFloat, b: CGFloat) {
#if os(OSX)
color = NSColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
#elseif os(iOS) || os(tvOS)
color = UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
#endif
}
public convenience init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
self.init(r: red * 255, g: green * 255, b: blue * 255)
}
var redColor: Int {
var r: CGFloat = 0
color.getRed(&r, green: nil, blue: nil, alpha: nil)
return Int(r * 255)
}
var greenColor: Int {
var g: CGFloat = 0
color.getRed(nil, green: &g, blue: nil, alpha: nil)
return Int(g * 255)
}
var blueColor: Int {
var b: CGFloat = 0
color.getRed(nil, green: nil, blue: &b, alpha: nil)
return Int(b * 255)
}
}