diff --git a/deps/ziti-sdk-c b/deps/ziti-sdk-c index 505c141..a838142 160000 --- a/deps/ziti-sdk-c +++ b/deps/ziti-sdk-c @@ -1 +1 @@ -Subproject commit 505c14139601a5743929729d7b6482ce5486802e +Subproject commit a8381424277e302e99eaa1f8eeb3c1054cfdbb85 diff --git a/lib/Ziti-Bridging-Header.h b/lib/Ziti-Bridging-Header.h index 87d00be..ce3dd47 100644 --- a/lib/Ziti-Bridging-Header.h +++ b/lib/Ziti-Bridging-Header.h @@ -20,12 +20,13 @@ limitations under the License. extern const char** ziti_all_configs; extern tls_context *default_tls_context(const char *ca, size_t ca_len); +extern void init_debug(uv_loop_t *loop); -extern int ziti_debug_level; -extern void uv_mbed_set_debug(int level, FILE *output); +typedef void (*log_writer)(int level, const char *loc, const char *msg, size_t msglen); +extern void ziti_set_log(log_writer log, uv_loop_t *loop); -char **copyStringArray(char *const arr[], int count); -void freeStringArray(char **arr); +extern int ziti_debug_level; +extern void ziti_logger_wrapper(int level, const char *file, unsigned int line, const char *func, const char *msg); -char *copyString(const char *str); -void freeString(char *str); +char **castStringArray(char *const arr[], int count); +char *castString(const char *str); diff --git a/lib/Ziti.swift b/lib/Ziti.swift index 5f27457..1d93b85 100644 --- a/lib/Ziti.swift +++ b/lib/Ziti.swift @@ -360,9 +360,8 @@ import Foundation return } - // must be done after ziti_init... - //ziti_debug_level = 11 - //uv_mbed_set_debug(5, stdout) + // set log level + ZitiLog.setLogLevel(.INFO) // Save off reference to current thread and run the loop if privateLoop { @@ -595,9 +594,8 @@ import Foundation mySelf?.perform { withArrayOfCStrings(macArray) { arr in - let cp = copyStringArray(arr, Int32(arr.count)) + let cp = castStringArray(arr, Int32(arr.count)) macCtx.cb(macCtx.ztx, ctx.id, cp, Int32(macArray.count)) - freeStringArray(cp) } } } @@ -624,15 +622,11 @@ import Foundation mySelf?.perform { // C SDK didn't use `const` for strings, so need to copy 'em - let cType = type != nil ? copyString(type!.cString(using: .utf8)) : nil - let cVersion = version != nil ? copyString(version!.cString(using: .utf8)) : nil - let cBuild = build != nil ? copyString(build!.cString(using: .utf8)) : nil + let cType = type != nil ? castString(type!.cString(using: .utf8)) : nil + let cVersion = version != nil ? castString(version!.cString(using: .utf8)) : nil + let cBuild = build != nil ? castString(build!.cString(using: .utf8)) : nil osCtx.cb(osCtx.ztx, osCtx.id, cType, cVersion, cBuild) - - freeString(cType) - freeString(cVersion) - freeString(cBuild) } } @@ -643,12 +637,12 @@ import Foundation } guard let query = mySelf?.postureChecks?.processQuery else { log.warn("query not configured", function: "onProcessQuery()") - cb(ztx, id, nil, false, nil, nil, 0) + cb(ztx, castString(id), nil, false, nil, nil, 0) return } let strPath = path != nil ? String(cString: path!) : "" - query(ZitiProcessContext(ztx, id, cb), strPath, Ziti.onProcessResponse) + query(ZitiProcessContext(ztx, castString(id), cb), strPath, Ziti.onProcessResponse) } static private let onProcessResponse:ZitiPostureChecks.ProcessResponse = { ctx, path, isRunning, hash, signers in @@ -660,21 +654,17 @@ import Foundation mySelf?.perform { // C SDK didn't use `const` for strings, so need to copy 'em - let cPath = copyString(path.cString(using: .utf8)) - let cHash = hash != nil ? copyString(hash!.cString(using: .utf8)) : nil + let cPath = castString(path.cString(using: .utf8)) + let cHash = hash != nil ? castString(hash!.cString(using: .utf8)) : nil if let signers = signers { withArrayOfCStrings(signers) { arr in - let cp = copyStringArray(arr, Int32(arr.count)) + let cp = castStringArray(arr, Int32(arr.count)) pCtx.cb(pCtx.ztx, ctx.id, cPath, isRunning, cHash, cp, Int32(signers.count)) - freeStringArray(cp) } } else { pCtx.cb(pCtx.ztx, pCtx.id, cPath, isRunning, cHash, nil, 0) } - - freeString(cPath) - freeString(cHash) } } @@ -700,9 +690,8 @@ import Foundation mySelf?.perform { // C SDK didn't use `const` for strings, so need to copy 'em - let cDomain = domain != nil ? copyString(domain!.cString(using: .utf8)) : nil + let cDomain = domain != nil ? castString(domain!.cString(using: .utf8)) : nil dCtx.cb(dCtx.ztx, dCtx.id, cDomain) - freeString(cDomain) } } diff --git a/lib/ZitiLog.swift b/lib/ZitiLog.swift index 8f6c886..5f12258 100644 --- a/lib/ZitiLog.swift +++ b/lib/ZitiLog.swift @@ -14,80 +14,194 @@ See the License for the specific language governing permissions and limitations under the License. */ import Foundation -import os.log -// For now just implement with OSLog... -class ZitiLog { - var oslog:OSLog +/// Logger class the uses Ziti C SDK's logging feature +public class ZitiLog { + var category:String + static var needDebugInit = true - init(_ category:String = "ziti") { - oslog = OSLog(subsystem: "io.netfoundry.ziti", category: category) + /// Maps to Ziti CSDK log levels, which cannot be imported directly + public enum DebugLevel : Int32 { + case NONE = 0, ERROR, WARN, INFO, DEBUG, VERBOSE, TRACE } - init(_ aClass:AnyClass) { - oslog = OSLog(subsystem: "io.netfoundry.ziti", category:String(describing: aClass)) + /// Initial logger + /// + /// - Parameters: + /// - category: descriptive name to differentiate unique logging areas + /// - loop: uv_loop for logger + public init(_ category:String = "CZiti", _ loop:UnsafeMutablePointer! = uv_default_loop()) { + self.category = category + if ZitiLog.needDebugInit { + ZitiLog.needDebugInit = false + setenv("ZITI_TIME_FORMAT", "utc", 1) + init_debug(loop) + } + } + + /// Initial logger + /// + /// - Parameters: + /// - aClass: use name of this class as the loggng categy + /// - loop: uv_loop for logger + public init(_ aClass:AnyClass, _ loop:UnsafeMutablePointer! = uv_default_loop()) { + //category = String(describing: aClass) + category = "CZiti" + if ZitiLog.needDebugInit { + ZitiLog.needDebugInit = false + setenv("ZITI_TIME_FORMAT", "utc", 1) + init_debug(loop) + } + } + + /// Set the system-wide log level + /// + /// - Parameters: + /// - level: only log messages at this level or higher (more severe) + public class func setLogLevel(_ level:DebugLevel) { + ziti_debug_level = level.rawValue + } + + /// Set a custom logger + /// + /// - Parameters: + /// - logger: customer logging function + /// - loop: uv_loop for logger + public class func setCustomerLogger(_ logger: @escaping log_writer, _ loop:UnsafeMutablePointer! = uv_default_loop()) { + // - TODO: Swiftify when updating for upcoming C SDK logging PR + ziti_set_log(logger, loop) + } + + /// Log a message at `.TRACE` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func trace(_ msg:String, + file:StaticString=#file, + function:StaticString=#function, + line:UInt=#line) { + log(.TRACE, msg, file, function, line) + } + + /// Log a message at `.VERBOSE` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func verbose(_ msg:String, + file:StaticString=#file, + function:StaticString=#function, + line:UInt=#line) { + log(.VERBOSE, msg, file, function, line) } - func debug(_ msg:String, + /// Log a message at `.DEBUG` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func debug(_ msg:String, file:StaticString=#file, function:StaticString=#function, line:UInt=#line) { - guard oslog.isEnabled(type: .debug) else { return } - log(.debug, msg, file, function, line) + log(.DEBUG, msg, file, function, line) } - func info(_ msg:String, + /// Log a message at `.INFO` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func info(_ msg:String, file:StaticString=#file, function:StaticString=#function, line:UInt=#line) { - log(.info, msg, file, function, line) + log(.INFO, msg, file, function, line) } - func warn(_ msg:String, + /// Log a message at `.WARN` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func warn(_ msg:String, file:StaticString=#file, function:StaticString=#function, line:UInt=#line) { - log(.error, "(warn) \(msg)", file, function, line) + log(.WARN, "\(msg)", file, function, line) } - func error(_ msg:String, + /// Log a message at `.ERROR` level + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func error(_ msg:String, file:StaticString=#file, function:StaticString=#function, line:UInt=#line) { - log(.error, msg, file, function, line) + log(.ERROR, msg, file, function, line) } - func wtf(_ msg:String, + /// Log a message at `.ERROR` level with "what a terrible failure" designation + /// + /// - Parameters: + /// - msg: message to log + /// - file: name of the file that makes this log message + /// - function: name of the function that makes this log message + /// - line: line number where this message was logged + public func wtf(_ msg:String, file:StaticString=#file, function:StaticString=#function, line:UInt=#line) { - log(.fault, msg, file, function, line) + log(.ERROR, "(WTF) \(msg)", file, function, line) } - private func typeToString(_ t:OSLogType) -> String { + private func levelToString(_ t:DebugLevel) -> String { var tStr = "" switch t { - case .debug: tStr = "DEBUG" - case .info: tStr = "INFO" - case .error: tStr = "ERROR" - case .fault: tStr = "WTF" - default: tStr = "" + case .NONE: tStr = "NONE " + case .ERROR: tStr = "ERROR " + case .WARN: tStr = "WARN " + case .INFO: tStr = "INFO " + case .DEBUG: tStr = "DEBUG " + case .VERBOSE: tStr = "VERBOSE" + case .TRACE: tStr = "TRACE " } return tStr } - private func log(_ type:OSLogType, _ msg:String, + private func log(_ level:DebugLevel, _ msg:String, _ file:StaticString, _ function:StaticString, _ line:UInt) { - - let file = URL(fileURLWithPath: String(describing: file)).deletingPathExtension().lastPathComponent + let file = "\(category):" + URL(fileURLWithPath: String(describing: file)).lastPathComponent var function = String(describing: function) if function.contains("(") { function.removeSubrange(function.firstIndex(of: "(")!...function.lastIndex(of: ")")!) } - let tStr = typeToString(type) - os_log("%{public}@\t%{public}@.%{public}@():%ld %{public}@", log:oslog.self, type:type, tStr, file, function, line, msg) + //let tStr = levelToString(type) + //fputs("[\(Date())] \(tStr) \(category):\(file):\(line) \(function)(): \(msg)\n", stderr) + if level.rawValue <= ziti_debug_level { + ziti_logger_wrapper(level.rawValue, + file.cString(using: .utf8), + UInt32(line), + function.cString(using: .utf8), + msg.cString(using: .utf8)) + } } } diff --git a/lib/ZitiUrlProtocol.swift b/lib/ZitiUrlProtocol.swift index 6d355db..ca9dc62 100644 --- a/lib/ZitiUrlProtocol.swift +++ b/lib/ZitiUrlProtocol.swift @@ -88,7 +88,7 @@ import Foundation } let svcName = String(cString: zs.name) - if status == ZITI_SERVICE_UNAVAILABLE || ((zs.perm_flags & ZITI_CAN_DIAL) == 0) { + if status == ZITI_SERVICE_UNAVAILABLE || ((zs.perm_flags & Int32(ZITI_CAN_DIAL)) == 0) { interceptsLock.lock() intercepts = intercepts.filter { $0.value.name != svcName } interceptsLock.unlock() diff --git a/lib/ziti.c b/lib/ziti.c index 642be10..16aff71 100644 --- a/lib/ziti.c +++ b/lib/ziti.c @@ -20,26 +20,21 @@ limitations under the License. static const char* _ziti_all[] = { "all", NULL }; +extern void +ziti_logger(int level, const char *file, unsigned int line, const char *func, const char *fmt, ...); + +void ziti_logger_wrapper(int level, const char *file, unsigned int line, const char *func, const char *msg) { + ziti_logger(level, file, line, func, "%s", msg); +} const char** ziti_all_configs = _ziti_all; -char **copyStringArray(char *const arr[], int count) { +char **castStringArray(char *const arr[], int count) { if (count == 0) return 0; - - size_t sz = sizeof(char**); - char **arrCpy = calloc((count + 1), sz); - memcpy(arrCpy, arr, count * sz); - return arrCpy; + return (char **)arr; } -void freeStringArray(char **arr) { - if (arr) free(arr); +char *castString(const char *str) { + return (char *)str; } -char *copyString(const char *str) { - return strdup(str); -} - -void freeString(char *str) { - if (str) free(str); -}