Skip to content
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

Capture Logs from NSLog as Breadcrumbs #1247

Open
fzyzcjy opened this issue Jul 24, 2021 · 19 comments
Open

Capture Logs from NSLog as Breadcrumbs #1247

fzyzcjy opened this issue Jul 24, 2021 · 19 comments

Comments

@fzyzcjy
Copy link

fzyzcjy commented Jul 24, 2021

Environment

How do you use Sentry?
Sentry SaaS (sentry.io) or self-hosted/on-premise (which version?)
saas

Which SDK and version?
e.g: JavaScript 5.11.1, .NET 1.2.0
ios

Steps to Reproduce

use sample

Expected Result

want to automatically capture logs to sentry breadcrumb

Actual Result

Cannot automatically capture logs to sentry breadcrumb

thanks!

@philipphofmann
Copy link
Member

Hey @fzyzcjy, which types of logs are you referring to? Would you please post some code snippets? Why do you want your logs as breadcrumbs anyway?

@fzyzcjy
Copy link
Author

fzyzcjy commented Jul 26, 2021

@philipphofmann you know, swift's log, objc's log. e.g. these https://stackoverflow.com/questions/25951195/swift-print-vs-println-vs-nslog

because logs provide precious clues when bugs comes!

@philipphofmann
Copy link
Member

We currently don't support redirecting the output of NSLog, Swift's Logger, or println. They use stderr and/or log messages to the Apple System Logging (asl) facility. You could maybe redirect stderr to SentryBreadcrumbs, but I guess that's doesn't make much sense. Furthermore, you shouldn't use NSLog in release builds, because its performance is not the best. Maybe you can use a logging framework like CocoaLumberjack, that allows you to redirect the log messages. You could also write your own logger, that uses NSLog in debug and SentryBreadcrumbs in release.

@fzyzcjy
Copy link
Author

fzyzcjy commented Jul 28, 2021

@philipphofmann Thanks for the reply! However, I see some third party libs use NSLog to print out things. Then how can I capture them?

@philipphofmann
Copy link
Member

philipphofmann commented Oct 28, 2021

Sorry for the late reply. Why do you want to capture third-party logs, @fzyzcjy? Just to understand your use case.

@fzyzcjy
Copy link
Author

fzyzcjy commented Oct 28, 2021

@philipphofmann b/c I use some third-party libs. Some of them only output logs to NSLog or something like that. And you know, in production environment, it is critical to capture logs, such that we can have more information when bug happens

@philipphofmann philipphofmann moved this to Needs Discussion in Mobile & Cross Platform SDK Nov 9, 2021
@philipphofmann philipphofmann changed the title Cannot automatically capture logs to sentry breadcrumb Capture Logs from NSLog as Breadcrumbs Nov 17, 2021
@philipphofmann
Copy link
Member

philipphofmann commented Nov 17, 2021

Java, .NET, Python already have a similar feature. We need to investigate how we can hook into NSLog so we achieve this. One idea would be to redirect the stderr to a memory stream or something. Do you @fzyzcjy maybe have any input on how we could achieve this?

Worth pointing out that os_log is the latest API. See #1461

@fzyzcjy
Copy link
Author

fzyzcjy commented Nov 17, 2021

I am not pretty sure how to achieve this, since I am not an expert in ios (but mostly doing flutter things). Your suggestions seem promising!

@matthewreimer
Copy link
Contributor

matthewreimer commented Jun 15, 2022

I'm very interested in this feature for the extra clues that might be in logs.

As of iOS 15, an app can get its own logs:

if let logStore = try? OSLogStore(scope: .currentProcessIdentifier) {
    let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
    if let allEntries = try? logStore.getEntries(at: oneHourAgo) {
        for entry in allEntries.compactMap({ $0 as? OSLogEntryLog }) {
            print("entry: \(entry.date) subsystem \(entry.subsystem) message \(entry.composedMessage)")
        }
    }
}

It seems to be a common convention to specify bundleIdentifier as the subsystem when creating the Logger; some also use the class name for category but either of these can be any string. So the logs could be filtered thusly:

if let logStore = try? OSLogStore(scope: .currentProcessIdentifier) {
    let oneHourAgo = logStore.position(date: Date().addingTimeInterval(-3600))
    if let allEntries = try? logStore.getEntries(at: oneHourAgo,
                                                 matching: NSPredicate(format: "subsystem == %@", Bundle.main.bundleIdentifier!)) {
        for entry in allEntries.compactMap({ $0 as? OSLogEntryLog }) {
            print("entry: \(entry.date) subsystem \(entry.subsystem) message \(entry.composedMessage)")
        }
    }
}

@matthewreimer
Copy link
Contributor

Also I see NSLog output in these logs too, with a subsystem of message (the leading space seems to be significant).

@philipphofmann
Copy link
Member

@philipphofmann philipphofmann moved this from Needs More Information to Needs Investigation in Mobile & Cross Platform SDK Jun 20, 2022
@garriguv
Copy link

garriguv commented Oct 5, 2022

FYI, I've been investigating this as well.

I started by experimenting with the following snippet to send OSLog entries to Sentry:
https://gist.github.com/garriguv/b5462cf629d8c8474d9b8474ca6d0744

The caveat is that the OSLogStore is very slow, so we only get a batch of logs every 10-15 seconds, which means that you'll likely miss the logs leading up to a crash.

A better approach could be to attach the logs from the last hour as breadcrumbs with every Sentry event using the beforeSend hook. It would look like this: https://gist.github.com/garriguv/4d2606862ba72b01a206c4ad3e8138c0

While the latter option works well for messages, it unfortunately does not work for crashes since they are sent the next time the application starts. In that case, we only get the logs from the last latest app launch, not any of the prior launches.
This is likely because the OSLogStore is instantiated with the .currentProcessIdentifier scope, and the process identifier differs across app launches.
See: https://developer.apple.com/forums/thread/700321?answerId=704363022#704363022

@philipphofmann
Copy link
Member

Thank you, @garriguv, for the update. 👏

A better approach could be to attach the logs from the last hour as breadcrumbs with every Sentry event using the beforeSend hook

Are these up to date or also 15 seconds delayed?

In that case, we only get the logs from the last app launch, not the prior launches.

Do you mean logs from the last app launch that crashed? Wouldn't that be enough?

@garriguv
Copy link

garriguv commented Oct 6, 2022

Do you mean logs from the last app launch that crashed? Wouldn't that be enough?

I meant the logs from the latest app launch, the one after the crash happened, which is not enough. I updated my post to clarify that point.

Are these up to date or also 15 seconds delayed?

I actually don't know. I think that building a little test bench project is the correct next step here. Maybe a good idea for your upcoming Hacktoberfest? 😉

@philipphofmann
Copy link
Member

philipphofmann commented Oct 6, 2022

Hacktoberfest is actually for contributing to open source. I added the tag because I thought it might be something a contributor could have a shot at.

Thanks for the update, @garriguv.

@mplorentz
Copy link

Reading the application logs that led up to a crash is something I also have been missing a lot with Sentry. It's a feature I'm used to from Firebase/Crashlytics and Bugsnag. Breadcrumbs intend to solve the same problem but they only capture a small fraction of the information developers typically print to the console.

We already have a custom "report a bug" feature in our app which attaches the logs. My initial thought was that I could just attach these logs to a Sentry crash. Here is how we did that with Bugsnag, there is a closure you pass in when initializing Bugsnag which allows you to attach information to a crash when it happens. Unfortunately it doesn't look like this is possible in Sentry, as the docs state "Please note that attachments don't work yet with crashes.".

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 2 Jan 9, 2024
@kahest kahest moved this from Needs Investigation to Needs Discussion in Mobile & Cross Platform SDK Jan 10, 2024
@philipphofmann
Copy link
Member

@mplorentz, adding info to a crash while it happens will be possible with #3408, but I can't give you an ETA.

You could try adding your logs, if they aren't too big, to the context which also ends up in crash events with something like

SentrySDK.configureScope { scope in
    scope.setContext(value: [
        "log 1": "login",
        "log 2" : "log out",
    ], key: "my_logs")
}

@kahest kahest moved this from Needs Discussion to Backlog in Mobile & Cross Platform SDK Jan 10, 2024
@mplorentz
Copy link

Thanks @philipphofmann. I subscribed to #3408. Our logs are pretty big right now so I'm not going to attempt the configureScope option, but maybe it is useful for others.

@getsantry getsantry bot moved this to Waiting for: Product Owner in GitHub Issues with 👀 2 Jan 10, 2024
@philipphofmann
Copy link
Member

@mplorentz, another idea is that you could use initialScope to add attachments and then remove them sometime later after initializing the SDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Status: Backlog
Development

No branches or pull requests

6 participants