【OSLog】How to log a Swift project




Overview

I found an article on the net that summarized how to use OSLog,

  • I wanted a working sample.
  • I am new to logging, so I wasn’t sure how to interpret the usage of OSLog.

So I summarized it in my own way.

What is OSLog?

It is a library for logging that is provided by Apple and can be used in Swift projects.
The official documentation is here.

Sample

https://github.com/Kuehar/OSLogSample

When the above code is run, eight buttons are lined up as shown below.



import SwiftUI
import OSLog

struct ContentView: View {
    let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "ApplicationCode")
    
    var body: some View {
        VStack {
            Button(action: {
                logger.trace("Trace Log")
            }, label: {
                Text("Trace")
            })
            Button(action: {
                logger.debug("Debug Log")
            }, label: {
                Text("Debug")
            })
            Button(action: {
                logger.info("Info Log")
            }, label: {
                Text("Info")
            })
            Button(action: {
                logger.notice("Notice Log")
            }, label: {
                Text("Notice")
            })
            Button(action: {
                logger.warning("Warning Log")
            }, label: {
                Text("Warning")
            })
            Button(action: {
                logger.error("Error Log")
            }, label: {
                Text("Error")
            })
            Button(action: {
                logger.critical("Critical Log")
            }, label: {
                Text("Critical")
            })
            Button(action: {
                logger.fault("Fault Log")
            }, label: {
                Text("Fault")
            })
        }
    }
}


Logs are displayed on the XCode console when each button on the screen is tapped.
Each type is described below.




If you want to display detailed information, you can set the information to be displayed by tapping the two toggle buttons in the window where the log is displayed.




If you check all the checkboxes, the information will be displayed like this.





Personally, I found it very useful that when you hover the cursor over the Row of the log, it tells you which code was logged and jumps to the source code when you click on the arrow mark, just like the image below.




To check the log, launch Console.app and search the ApplicationCode category in the search bar as follows: Notice,Warning,Error,Critical,Fault log.




Points of concern upon investigation.

1. Why not just use print debugging?

Come to think of it, I had never thought of a clear standard of usage.
I thought that it would be better to pick up fatal bugs in the log, but for variable-level display, isn’t print sufficient? That’s about the extent of my understanding.

I have tried to sort out print debugging and Log in my own way.

print debugging

Advantage.

  • Easy to use. Simply outputs text to the console, no special setup required.

Disadvantages.

  • Heavy use of print in a production environment may adversely affect performance.
  • XCode deletes print debugging information after each build (you can check the console output for each build in the build history, but it is difficult to tell which build it is after many builds), so it is inconvenient when you want to search for it.
  • When reading the source code, it is a bit annoying when there is a makeshift print() statement (personal thought).

Logging with OSLog

Advantages:

  • Logs can be categorized and displayed at appropriate levels.
  • Can be configured to control log output destination and level.
  • Useful logs of highly critical processes are kept, allowing troubleshooting in the production environment.

Disadvantage:

  • Generally a little more complicated to configure and use than print.

I’ve organized the contents of each of these, but basically, OSLog is good enough, right? I feel that it is good to use Console.app.
Using Console.app makes it easier to debug because it is easier to search for past logs.

I personally feel comfortable using print in my own local environment as a basic line of thinking, but I would like to eliminate the print debugging when I push.
I think it is kinder to declare the information that you think is necessary by debugging or something if necessary.

2. There are many types, but what are the standards for using different types?

There seems to be a standard way to divide the information among them, and it seems to be good to basically follow it.
I have done some research and found that the following classifications are used in many cases.

                                     Purpose Usage Criteria Concrete example ex.for logging application logins
Trace

Used to trace highly specific information or the processing status of an entire application Information for tracing the detailed operation of each step, method call, loop, etc. of an application. ・ Trace the progress of a large amount of data processing or the execution steps of a detailed algorithm
Debug

Used to trace debug information and detailed steps Information to help developers understand the behavior of the application, such as values of variables, function calls, processing flow, etc. ・Get user name and password
・Displaying the login screen
Info

Used to manage general information and processing progress Important application events such as start and end of important operations, user actions, network requests, etc. ・Record of user login attempts
・A record of the login process being initiated.
Notice

Used to notify notifiable events during normal operation Situations that are normal behavior but worthy of special attention, especially important application events ・When initialization of a specific module is completed
・When a connection to an external service is successfully established
Warning

Used to notify that a problem or anomaly has occurred but does not affect the normal operation of the application Unexpected situations, potential problems, possible loss of data, or other situations requiring attention ・Warning when passwords are weak.
・Warning when the number of login attempts exceeds a certain number
Error

Used to notify of errors or critical problems that would prevent the application from working properly Situations in which the application does not behave as expected, such as the occurrence of errors, failed operations, or unexpected situations ・Error when a user name cannot be found.
・Error if the password is incorrect.
Critical Used to notify that a system condition is critical and needs to be addressed immediately A situation in which the application does not behave as expected, such as the occurrence of an error, a failed operation, or an unexpected situation ・When communication with the server completely fails
・When an attempted security breach is detected.
Fault Used to notify that a system has suffered a fatal failure Circumstances in which the system condition is fatal and may result in application stoppage or severe loss ・When the entire system crashes ・When the entire system crashes
・When the database becomes unavailable

3. How do I get logs from any file in Project?

I moved the declarations around logger from within ContentView to AppLogger, so the code in SwiftUI files will be cleaner.

With the change, the logging process in ContentView has changed from logger.trace("Trace Log") to a format like AppLogger.shared.logger.trace("Trace Log").

Some people seem to be writing in extensions, but I guess it depends on the operation of the team.

import Foundation
import OSLog

class AppLogger {
    static let shared = AppLogger()
    let logger: Logger
    
    private init() {
        self.logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "ApplicationCode")
    }
}


import SwiftUI

struct ContentView: View {  
    var body: some View {
        VStack {
            Button(action: {
                AppLogger.shared.logger.trace("Trace Log")
            }, label: {
                Text("Trace")
            })
            Button(action: {
                AppLogger.shared.logger.debug("Debug Log")
            }, label: {
                Text("Debug")
            })
            Button(action: {
                AppLogger.shared.logger.info("Info Log")
            }, label: {
                Text("Info")
            })
            Button(action: {
                AppLogger.shared.logger.notice("Notice Log")
            }, label: {
                Text("Notice")
            })
            Button(action: {
                AppLogger.shared.logger.warning("Warning Log")
            }, label: {
                Text("Warning")
            })
            Button(action: {
                AppLogger.shared.logger.error("Error Log")
            }, label: {
                Text("Error")
            })
            Button(action: {
                AppLogger.shared.logger.critical("Critical Log")
            }, label: {
                Text("Critical")
            })
            Button(action: {
                AppLogger.shared.logger.fault("Fault Log")
            }, label: {
                Text("Fault")
            })
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

コメント

このブログの人気の投稿

Braveブラウザの同期機能をiPhoneで設定した話。

failed: unable to get local issuer certificate (_ssl.c:1123)と出たので解決した話

自作のChrome Extensionをインポートした時に "Invalid value for 'content_scripts[0].matches[0]': Empty path."というエラーが出たので解決した