Skip to content

DnV1eX/GoogleCloudLogging

Repository files navigation

GoogleCloudLogging

Event logging for client applications on Apple platforms with support for offline work and automatic upload to Google Cloud (GCP). The package depends on SwiftLog - 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 file format and bulk uploaded to GCP using the Cloud Logging API v2 at time intervals, upon defined event or explicit request.

And yes, it logs itself! (with recursion protection) 🤘

Rationale

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:

Library FirebaseAnalytics GoogleCloudLogging
Platform Mobile only. Even Catalyst is not currently supported. All modern Apple's OSs. It is essential for development of universal SwiftUI apps.
Source code Closed source. All application and users data is available to Google. Open source. A few hundred lines of pure Swift, no implicit data submission.
Dependences Part of the Firebase SDK. Brings a bunch of Objective-C/C++ code with runtime swizzling etc. Only relies on SwiftLog and Apple's embedded frameworks.
Distribution CocoaPods/Carthage. SwiftPM is currently cannot be supported due to closed source and dependencies. SwiftPM, which is preferred as integrated with the Swift build system.
Backend Google Analytics for Firebase. Includes some predefined marketing tools. GCP Operations (formerly Stackdriver). Flexible custom log views, metrics, notifications, export etc.
Integration Registration of your app in Google is required. Only need to generate an access key.
Logging Proprietary logging functions and implicit usage tracking. SwiftLog logging API. Single line connection of logging backend.

Getting Started

Add Package Dependency

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.

Create Service Account

In your web browser, open the Google Cloud Console 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.

Setup Logging

  1. Import both SwiftLog and GoogleCloudLogging modules:
import Logging
import GoogleCloudLogging
  1. Register the logging backend once after the app launch:
LoggingSystem.bootstrap(GoogleCloudLogHandler.init)

Alternatively, you can register several backends, for example, in order to send logs to both GCP and the Xcode console:

LoggingSystem.bootstrap { MultiplexLogHandler([GoogleCloudLogHandler(label: $0), StreamLogHandler.standardOutput(label: $0)]) }
  1. Configure GoogleCloudLogHandler:
do {
    try GoogleCloudLogHandler.setup(serviceAccountCredentials: Bundle.main.url(forResource: /* GCP private key file name */, withExtension: "json")!, clientId: UIDevice.current.identifierForVendor)
} catch {
    // Log GoogleCloudLogHandler setup error
}

If UIKit is not available, you can generate random clientId using UUID() and store it between the app launches.

You can customize GoogleCloudLogHandler's static variables which are all thread safe and documented in the source code.

It is recommended to explicitly upload logs calling GoogleCloudLogHandler.upload() when hiding or exiting the app.

How to Use

Emit Logs

  1. Import SwiftLog module into the desired file:
import Logging
  1. Create logger which can be a type, instance, or global constant or variable:
static let logger = Logger(label: /* Logged class name */)

You can customize the minimum emitted log level and set the logger metadata.

  1. Emit log messages in a certain log level:
logger.info(/* Logged info message */)
logger.error(/* Logged error message */, metadata: [LogKey.error: "\(error)"])

It is a good practice to define typealias LogKey = GoogleCloudLogHandler.MetadataKey and extend it with your custom keys rather than use string literals.

GoogleCloudLogHandler.globalMetadata takes precedence over Logger metadata which in turn takes precedence over log message metadata in case of key overlapping.

Analyze Logs

In your web browser, open the GCP Operations Logging 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.

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

Click on clientId label value of the desired log entry and pick "Show matching entries" in order to view logs from the same app instance only.

Supported Platforms

  • iOS 11+
  • iPadOS 13+
  • macOS 10.13+
  • tvOS 11+
  • watchOS 4+

License

Copyright © 2020 DnV1eX. All rights reserved. Licensed under the Apache License, Version 2.0.