# OSLog

As developers, we are often faced with bugs that require us to debug our code. The most common way to do this (and the way it is taught in many CS courses at Cornell) is to use print statements. Although print statements are a very powerful tool to help debug our code, we can go beyond that and use a library called **OSLog**.

### What is OSLog?

**OSLog** is Apple’s recommended library for logging and is a replacement for `print` statements and `NSLog`. OSLog allows us to mark different logging levels such as “warning” and “error” as well as structuring our app’s logging into categories that we can create. Additionally, it works perfectly with Xcode 15’s new logging console, enriching our debugging experience even further.

### Getting Started with OSLog

To get started, let’s create a file in our project directory called `Logger.swift`. Inside of the file, add the following code:

{% code title="Logger.swift" %}

```swift
import OSLog

extension Logger {

    /// The logger's subsystem.
    private static var subsystem = Bundle.main.bundleIdentifier!

    // NOTE: Replace the categories below with your own choosing.

    /// All logs related to data such as decoding error, parsing issues, etc.
    static let data = Logger(subsystem: subsystem, category: "data")

    /// All logs related to services such as network calls, location, etc.
    static let services = Logger(subsystem: subsystem, category: "services")

    /// All logs related to tracking and analytics.
    static let statistics = Logger(subsystem: subsystem, category: "statistics")

}
```

{% endcode %}

1. We first import this library with `import OSLog` in order to use all functionality provided by it.
2. We then create an **extension** of the `Logger` class which is already defined in OSLog.
3. Every `Logger` instance requires two things: a subsystem and category.
   1. We define a **static variable** representing our subsystem which should be unique. The best way to unsure uniqueness is to use our bundle identifier.
   2. We can then create our `Logger` instances with a category of our choice. The categories shown above are some common ones.

### Writing Logs

To write a log, we can use the following syntax:

```swift
Logger.services.info("Location Restricted")
```

We use the static variable `services` that we created earlier (which is a `Logger` object), followed by a log level (in this case `info`). There are many log levels that we can choose from, each being displayed differently in the Xcode console.

* **default (notice)**: The default log level which should be avoided. Our logs should be more specific.
* **info**: Log information that may be helpful but is not necessary for debugging.
* **debug**: We use this level during development while actively debugging.
* **trace:** Same as debug but for tracing the program flow of our code.
* **warning:** Warning-level messages that do not cause any failure or critical errors.
* **error**: Error-level messages for critical errors and failures.
* **fault**: Fault-level messages for system-level or multi-process errors.
* **critical:** Same as fault.

We also need to make sure that our console has the proper Metadata selected to display the logs properly:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FSNzxERZVNVfo5oiChBrS%2FUntitled.png?alt=media&#x26;token=f351bb49-e7ee-4c38-9fa6-849310394ad4" alt="" width="156"><figcaption></figcaption></figure>

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FkhosedqK7rrJBz0D9m8X%2FUntitled.png?alt=media&#x26;token=483601cd-22ca-40d1-9ada-99e8fdd77fee" alt="" width="563"><figcaption><p>Console outputs for different log levels.</p></figcaption></figure>

### Data Privacy

When logging, we need to consider data privacy. For example, if we wanted to log a user’s birthday, we can use the following code:

```swift
let birthday = "February 6, 2004"
Logger.data.info("User's birthday is \(birthday, privacy: .private)")
```

We use **string interpolation** to output the value of the `birthday` constant and mark it as **private**. We want to do this to prevent external apps such as Console to be able to view sensitive information in our logs.

### Console App

For more advanced logging, we can use the Console app to read our logs. The Console app supports optimized logging structures with alignments which improves readability. Additionally, we can filter logs from multiple devices, categories, and log levels. Learn more about logging in the [Apple Documentation](https://developer.apple.com/documentation/os/logging).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/textbook/debugging/oslog.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
