-
Notifications
You must be signed in to change notification settings - Fork 301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding support for privacy level in string interpolation #204
Comments
I noticed some advice regarding privacy here. Would be great to have a section in the docs about this. |
That is a good idea @nashysolutions. would you or @Frizlab like to make a PR with proposed language? I suspect we may also want to consider a new metadata type for sensitive data that the log backend can reduct |
We've implemented a similar mechanism in our local code - is this something that might be generally useful? extension Logger.MetadataValue {
/// The different styles of privacy masks that can be applied to a metadata value.
internal enum PrivacyMask {
/// The value will be hashed and converted into an 8 character hex representation.
case hash
/// Replaces the value with `*****`.
case redact
}
/// Replaces the value with `*****`.
///
/// This is great for when the actual value is not of importance and should be masked when not debugging.
///
/// For example:
///
/// let logger: Logger = ...
/// logger.info(
/// "replaced value with mask pattern",
/// metadata: [
/// "password": .mask(user.password)
/// ]
/// )
public static func mask(_ value: Any) -> Logger.MetadataValue {
return .stringConvertible(MaskedValue(value, mask: .redact))
}
/// The value will be hashed and converted into an 8 character hex representation.
///
/// This is great for when identity of value between individual logs is important, but the actual value should still be masked.
///
/// For example:
///
/// let logger: Logger = ...
/// logger.info(
/// "obfuscated value",
/// metadata: [
/// "ip_address": .hash(user.ipAddress)
/// ]
/// )
public static func hash(_ value: Any) -> Logger.MetadataValue {
return .stringConvertible(MaskedValue(value, mask: .hash))
}
}
internal struct MaskedValue: CustomStringConvertible {
internal let underlying: Any
private let mask: Logger.MetadataValue.PrivacyMask
internal var description: String {
switch mask {
case .hash: return self.hash("\(self.underlying)")
case .redact: return "*****"
}
}
fileprivate init(_ value: Any, mask: Logger.MetadataValue.PrivacyMask) {
self.underlying = value
self.mask = mask
}
private func hash(_ value: String) -> String {
var hasher = Hasher()
hasher.combine(value)
return "\(String(format: "%x", hasher.finalize()))"
}
} |
Here's an example of the switch metadataValue {
case let .stringConvertible(maskedValue as MaskedValue) where self.logLevel <= .debug:
return "\(maskedValue.underlying)"
default: return "\(metadataValue)"
} |
@Mordil @tomerd @Frizlab I actually open sourced exactly this around 2 years ago. It was discussed with the team here and on Swift Forums but was deemed inappropriate for this library. So I pulled
|
@shaps80 Do you have links to the discussions where it was determined this was inappropriate for the library to offer directly? |
Yeah, https://forums.swift.org/t/swiftlog-stringinterpolation/52313/3 On this repo there was also: #208 |
@tomerd For apps I think adding privacy works just fine. For libraries it's IMHO not possible to sensibly annotate. Take a URL, some apps have sensitive URLs, other apps don't but the HTTP client library couldn't know how it's used. My personal opinion is: If you need privacy, then
So the above message (
because an IMHO sensible LogHandler configuration would (for a hypothetical SuperCoolPrivacyLogHandler) could look something like
The reason is that IMHO only the application can know what has PII and what doesn't. If the HTTP client is only used for requests that never contain PII, then it would be safe to add If it becomes too tedious to list each and every field, then I would suggest a convention for your application: For example if you say that every metadata key that starts with I'm guessing the tl;dr is:
|
one thing to keep in mind is that the application is also a "producer" log events. its makes perfect sense to me that libraries do not force PII decision on the app, but its nice for the apps to be able to emit ones taking into account PII considerations. that said, I can see how this can be handled in a sophisticated enough handler / backend with nice configuration for this kind of settings |
Totally agree with everything. I guess I was trying to say doing something that adds privacy for the app only but ignores the libraries isn't any good. And yes, sophisticated LogHandlers are the way. I wish there was a properly configurable and featureful "logging middle-end" that would take care of these things once and for all. |
The retry implementation cannot know whether or not the error contains private information, so it should log the error and allow the user of the library to decide. As detailed [here](apple/swift-log#204 (comment)), the log handler can redact metadata values as needed.
On macOS, the (Apple’s) Logger object uses a custom
OSLogMessage
object which allows it to have a custom string interpolation with support for format arguments privacy levels.Would it be possible to add support for said string interpolation so we could finally have an efficient and fully feature-compatible OSLog
Logger
forswift-log
?Thanks!
The text was updated successfully, but these errors were encountered: