Skip to content

Commit 287947b

Browse files
committed
Increased accuracy of log timestamps up to nanoseconds. Removed templates of tests for Linux. Minor readme corrections.
1 parent 373a0a2 commit 287947b

File tree

5 files changed

+35
-36
lines changed

5 files changed

+35
-36
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# GoogleCloudLogging
22

3-
Event logging for client applications on [Apple platforms](#supported-platforms) with support for offline work and automatic upload to [Google Cloud (GCP)](https://cloud.google.com). The package depends on [SwiftLog](https://github.com/apple/swift-log) - an official logging API for Swift, so it can be easly integrated into the project and combined with other logging backends. Log events are stored locally in the [JSON Lines](http://jsonlines.org) file format and bulk uploaded to GCP using the [Cloud Logging API v2](https://cloud.google.com/logging/docs/reference/v2/rest) at time intervals, upon defined event or explicit request. _And yes, it logs itself! (with recursion protection)_ 🤘
3+
Event logging for client applications on [Apple platforms](#supported-platforms) with support for offline work and automatic upload to [Google Cloud (GCP)](https://cloud.google.com). The package depends on [SwiftLog](https://github.com/apple/swift-log) - an official logging API for Swift, so it can be easly integrated into the project and combined with other logging backends. Log events are stored locally in the [JSON Lines](http://jsonlines.org) file format and bulk uploaded to GCP using the [Cloud Logging API v2](https://cloud.google.com/logging/docs/reference/v2/rest) at time intervals, upon defined event or explicit request.
4+
5+
> And yes, it logs itself! (with recursion protection) 🤘
46
57
## Rationale
6-
Google recommended logging solution for client applications is Analytics framework, which is now part of the Firebase SDK. Here is a comparison of that framework and this library in terms of logging:
8+
Google-recommended logging solution for client applications is the Analytics framework, which is now part of the Firebase SDK. Here is a comparison of their framework and this library in terms of logging:
79
Library | FirebaseAnalytics | GoogleCloudLogging
810
--- | --- | ---
911
Platform | Mobile only. _Even Catalyst is not currently supported._ | All modern Apple's OSs. _It is essential for development of universal SwiftUI apps._
@@ -19,7 +21,9 @@ Logging | Proprietary logging functions and implicit usage tracking. | SwiftLog
1921
Open your application project in Xcode 11 or later, go to menu `File -> Swift Packages -> Add Package Dependency...` and paste the package repository URL `https://github.com/DnV1eX/GoogleCloudLogging.git`.
2022

2123
### Create Service Account
22-
In your web browser open the [Google Cloud Console](https://console.cloud.google.com) and create a new project. In `IAM & Admin -> Service Accounts` create a service account choosing `Logging -> Logs Writer` role. In the last step, create and download private key choosing `JSON` format. You need to include this file in your application bundle, just drag the file into the Xcode project and tick the desired targets in the file inspector.
24+
In your web browser, open the [Google Cloud Console](https://console.cloud.google.com) and create a new project. In `IAM & Admin -> Service Accounts` create a service account choosing `Logging -> Logs Writer` role. In the last step, create and download private key choosing `JSON` format. You need to include this file in your application bundle.
25+
26+
> Just drag the file into the Xcode project and tick the desired targets in the file inspector.
2327
2428
### Setup Logging
2529
1. Import both `SwiftLog` and `GoogleCloudLogging` modules:
@@ -74,7 +78,7 @@ logger.error(/* Logged error message */, metadata: [LogKey.error: "\(error)"])
7478
> `GoogleCloudLogHandler.globalMetadata` takes precedence over `Logger` metadata which in turn takes precedence over log message metadata in case of key overlapping.
7579
7680
### Analyze Logs
77-
In your web browser open the [GCP Operations Logging](https://console.cloud.google.com/logs) and select your project. You will see a list of logs for a given **time range** which can be filtered by **log name** _(logger label)_, **severity** _(log level)_, **text payload** _(message)_, **labels** _(metadata)_ etc. **Resource type** for logs produced by GoogleCloudLogHandler is always _Global_.
81+
In your web browser, open the [GCP Operations Logging](https://console.cloud.google.com/logs) and select your project. You will see a list of logs for a given **time range** which can be filtered by **log name** _(logger label)_, **severity** _(log level)_, **text payload** _(message)_, **labels** _(metadata)_ etc. **Resource type** for logs produced by GoogleCloudLogHandler is always _Global_.
7882

7983
> You can switch to the new Logs Viewer Preview that introduces new features, such as advanced log queries and histograms.
8084

Sources/GoogleCloudLogging/GoogleCloudLogging.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ class GoogleCloudLogging {
308308
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
309309
do {
310310
let encoder = JSONEncoder()
311-
encoder.dateEncodingStrategy = .iso8601WithFractionalSeconds
311+
encoder.dateEncodingStrategy = .iso8601WithNanoseconds
312312
let entries: [Log.Entry] = entries.map {
313313
var entry = $0
314314
entry.logName = Log.name(projectId: self.serviceAccountCredentials.projectId, logId: $0.logName)
@@ -342,13 +342,25 @@ extension Data {
342342

343343

344344

345+
extension ISO8601DateFormatter {
346+
347+
static func internetDateTimeWithNanosecondsString(from date: Date, timeZone: TimeZone = TimeZone(secondsFromGMT: 0)!) -> String {
348+
var string = ISO8601DateFormatter.string(from: date, timeZone: timeZone, formatOptions: .withInternetDateTime)
349+
var timeInterval = date.timeIntervalSinceReferenceDate
350+
if timeInterval < 0 {
351+
timeInterval += (-timeInterval * 2).rounded(.up)
352+
}
353+
string.insert(contentsOf: "\(timeInterval)".drop { $0 != "." }.prefix(10), at: string.index(string.startIndex, offsetBy: 19))
354+
return string
355+
}
356+
}
357+
358+
345359
extension JSONEncoder.DateEncodingStrategy {
346360

347-
static let iso8601WithFractionalSeconds = custom { date, encoder in
348-
let dateFormatter = ISO8601DateFormatter()
349-
dateFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
361+
static let iso8601WithNanoseconds = custom { date, encoder in
350362
var container = encoder.singleValueContainer()
351-
try container.encode(dateFormatter.string(from: date))
363+
try container.encode(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: date))
352364
}
353365
}
354366

@@ -369,7 +381,6 @@ extension CharacterSet {
369381
}
370382

371383

372-
373384
extension String {
374385

375386
func safeLogId() -> String {

Tests/GoogleCloudLoggingTests/GoogleCloudLoggingTests.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ final class GoogleCloudLoggingTests: XCTestCase {
8181
}
8282

8383

84+
func testISO8601DateFormatterNanoseconds() {
85+
86+
XCTAssertEqual(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: Date(timeIntervalSinceReferenceDate: 615695580)), "2020-07-06T02:33:00.0Z")
87+
XCTAssertEqual(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: Date(timeIntervalSinceReferenceDate: 615695580.235942)), "2020-07-06T02:33:00.235942Z")
88+
XCTAssertEqual(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: Date(timeIntervalSinceReferenceDate: 615695580.987654321)), "2020-07-06T02:33:00.9876543Z")
89+
XCTAssertEqual(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: Date(timeIntervalSinceReferenceDate: 0.987654321)), "2001-01-01T00:00:00.987654321Z")
90+
XCTAssertEqual(ISO8601DateFormatter.internetDateTimeWithNanosecondsString(from: Date(timeIntervalSinceReferenceDate: -0.9876543211)), "2000-12-31T23:59:59.012345678Z")
91+
}
92+
93+
8494
func testSafeLogId() {
8595

8696
XCTAssertEqual("My_class-1.swift".safeLogId(), "My_class-1.swift")
@@ -97,14 +107,4 @@ final class GoogleCloudLoggingTests: XCTestCase {
97107
logger.critical("LoggerMessage", metadata: ["MessageMetadataKey": "MessageMetadataValue"])
98108
Thread.sleep(forTimeInterval: 3)
99109
}
100-
101-
102-
static var allTests = [
103-
("testTokenRequest", testTokenRequest),
104-
("testEntriesWrite", testEntriesWrite),
105-
("testLogHandler", testLogHandler),
106-
("testDictionaryUpdate", testDictionaryUpdate),
107-
("testSafeLogId", testSafeLogId),
108-
("testGoogleCloudLogHandler", testGoogleCloudLogHandler),
109-
]
110110
}

Tests/GoogleCloudLoggingTests/XCTestManifests.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.

Tests/LinuxMain.swift

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)