| //===----------------- OSLogPrivacy.swift ---------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // This file defines the APIs for specifying privacy in the log messages and also |
| // the logic for encoding them in the byte buffer passed to the libtrace library. |
| |
| /// Privacy options for specifying privacy level of the interpolated expressions |
| /// in the string interpolations passed to the log APIs. |
| @frozen |
| public struct OSLogPrivacy { |
| |
| @usableFromInline |
| internal enum PrivacyOption { |
| case `private` |
| case `public` |
| case auto |
| } |
| |
| public enum Mask { |
| /// Applies a salted hashing transformation to an interpolated value to redact it in the logs. |
| /// |
| /// Its purpose is to permit the correlation of identical values across multiple log lines |
| /// without revealing the value itself. |
| case hash |
| case none |
| } |
| |
| @usableFromInline |
| internal var privacy: PrivacyOption |
| |
| @usableFromInline |
| internal var mask: Mask |
| |
| @_transparent |
| @usableFromInline |
| internal init(privacy: PrivacyOption, mask: Mask) { |
| self.privacy = privacy |
| self.mask = mask |
| } |
| |
| /// Sets the privacy level of an interpolated value to public. |
| /// |
| /// When the privacy level is public, the value will be displayed |
| /// normally without any redaction in the logs. |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| @inlinable |
| public static var `public`: OSLogPrivacy { |
| OSLogPrivacy(privacy: .public, mask: .none) |
| } |
| |
| /// Sets the privacy level of an interpolated value to private. |
| /// |
| /// When the privacy level is private, the value will be redacted in the logs, |
| /// subject to the privacy configuration of the logging system. |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| @inlinable |
| public static var `private`: OSLogPrivacy { |
| OSLogPrivacy(privacy: .private, mask: .none) |
| } |
| |
| /// Sets the privacy level of an interpolated value to private and |
| /// applies a `mask` to the interpolated value to redacted it. |
| /// |
| /// When the privacy level is private, the value will be redacted in the logs, |
| /// subject to the privacy configuration of the logging system. |
| /// |
| /// If the value need not be redacted in the logs, its full value is captured as normal. |
| /// Otherwise (i.e. if the value would be redacted) the `mask` is applied to |
| /// the argument value and the result of the transformation is recorded instead. |
| /// |
| /// - Parameters: |
| /// - mask: Mask to use with the privacy option. |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| @inlinable |
| public static func `private`(mask: Mask) -> OSLogPrivacy { |
| OSLogPrivacy(privacy: .private, mask: mask) |
| } |
| |
| /// Auto-infers a privacy level for an interpolated value. |
| /// |
| /// The system will automatically decide whether the value should |
| /// be captured fully in the logs or should be redacted. |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| @inlinable |
| public static var auto: OSLogPrivacy { |
| OSLogPrivacy(privacy: .auto, mask: .none) |
| } |
| |
| /// Auto-infers a privacy level for an interpolated value and applies a `mask` |
| /// to the interpolated value to redacted it when necessary. |
| /// |
| /// The system will automatically decide whether the value should |
| /// be captured fully in the logs or should be redacted. |
| /// If the value need not be redacted in the logs, its full value is captured as normal. |
| /// Otherwise (i.e. if the value would be redacted) the `mask` is applied to |
| /// the argument value and the result of the transformation is recorded instead. |
| /// |
| /// - Parameters: |
| /// - mask: Mask to use with the privacy option. |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| @inlinable |
| public static func auto(mask: Mask) -> OSLogPrivacy { |
| OSLogPrivacy(privacy: .auto, mask: mask) |
| } |
| |
| /// Return an argument flag for the privacy option., as defined by the |
| /// os_log ABI, which occupies four least significant bits of the first byte of the |
| /// argument header. The first two bits are used to indicate privacy and |
| /// the other two are reserved. |
| @inlinable |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| internal var argumentFlag: UInt8 { |
| switch privacy { |
| case .private: |
| return 0x1 |
| case .public: |
| return 0x2 |
| default: |
| return 0 |
| } |
| } |
| |
| @inlinable |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| internal var isAtleastPrivate: Bool { |
| switch privacy { |
| case .public: |
| return false |
| case .auto: |
| return false |
| default: |
| return true |
| } |
| } |
| |
| @inlinable |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| internal var needsPrivacySpecifier: Bool { |
| if case .hash = mask { |
| return true |
| } |
| switch privacy { |
| case .auto: |
| return false |
| default: |
| return true |
| } |
| } |
| |
| @inlinable |
| @_transparent |
| internal var hasMask: Bool { |
| if case .hash = mask { |
| return true |
| } |
| return false |
| } |
| |
| /// A 64-bit value obtained by interpreting the mask name as a little-endian unsigned |
| /// integer. |
| @inlinable |
| @_transparent |
| internal var maskValue: UInt64 { |
| // Return the value of |
| // 'h' | 'a' << 8 | 's' << 16 | 'h' << 24 which equals |
| // 104 | (97 << 8) | (115 << 16) | (104 << 24) |
| 1752392040 |
| } |
| |
| /// Return an os log format specifier for this `privacy` level. The |
| /// format specifier goes within curly braces e.g. %{private} in the format |
| /// string passed to the os log ABI. |
| @inlinable |
| @_semantics("constant_evaluable") |
| @_optimize(none) |
| internal var privacySpecifier: String? { |
| let hasMask = self.hasMask |
| var isAuto = false |
| if case .auto = privacy { |
| isAuto = true |
| } |
| if isAuto, !hasMask { |
| return nil |
| } |
| var specifier: String |
| switch privacy { |
| case .public: |
| specifier = "public" |
| case .private: |
| specifier = "private" |
| default: |
| specifier = "" |
| } |
| if hasMask { |
| if !isAuto { |
| specifier += "," |
| } |
| specifier += "mask.hash" |
| } |
| return specifier |
| } |
| } |
| |