diff --git a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt index 5501c7895..f504d91b1 100644 --- a/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt +++ b/android/src/main/java/expo/modules/xmtpreactnativesdk/XMTPModule.kt @@ -66,7 +66,9 @@ import org.xmtp.proto.message.contents.Invitation.ConsentProofPayload import org.xmtp.proto.message.contents.PrivateKeyOuterClass import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.GroupPermissionPreconfiguration import uniffi.xmtpv3.org.xmtp.android.library.libxmtp.PermissionOption +import java.io.BufferedReader import java.io.File +import java.io.InputStreamReader import java.util.Date import java.util.UUID import kotlin.coroutines.Continuation @@ -1564,13 +1566,29 @@ class XMTPModule : Module() { val client = clients[inboxId] ?: throw XMTPException("No client") client.contacts.isGroupAllowed(groupId) } - AsyncFunction("isGroupDenied") { inboxId: String, groupId: String -> logV("isGroupDenied") val client = clients[inboxId] ?: throw XMTPException("No client") client.contacts.isGroupDenied(groupId) } - } + + AsyncFunction("exportNativeLogs") Coroutine { -> + withContext(Dispatchers.IO) { + try { + val process = Runtime.getRuntime().exec("logcat -d") + val bufferedReader = BufferedReader(InputStreamReader(process.inputStream)) + + val log = StringBuilder() + var line: String? + while (bufferedReader.readLine().also { line = it } != null) { + log.append(line).append("\n") + } + log.toString() + } catch (e: Exception) { + e.message + } + } + } // // Helpers diff --git a/example/src/tests/groupTests.ts b/example/src/tests/groupTests.ts index c6fa603eb..78d6524a7 100644 --- a/example/src/tests/groupTests.ts +++ b/example/src/tests/groupTests.ts @@ -1,12 +1,8 @@ +import { Wallet } from 'ethers' import RNFS from 'react-native-fs' import { DecodedMessage } from 'xmtp-react-native-sdk/lib/DecodedMessage' -import { - Test, - assert, - createClients, - delayToPropogate, -} from './test-utils' +import { Test, assert, createClients, delayToPropogate } from './test-utils' import { Client, Conversation, @@ -17,7 +13,6 @@ import { GroupUpdatedContent, GroupUpdatedCodec, } from '../../../src/index' -import { Wallet } from 'ethers' export const groupTests: Test[] = [] let counter = 1 diff --git a/example/src/tests/tests.ts b/example/src/tests/tests.ts index ad1b6c6c6..626e60ce6 100644 --- a/example/src/tests/tests.ts +++ b/example/src/tests/tests.ts @@ -8,7 +8,7 @@ import { PrivateKeyAccount } from 'viem' import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts' import { DecodedMessage } from 'xmtp-react-native-sdk/lib/DecodedMessage' -import { Test, assert, delayToPropogate } from './test-utils' +import { Test, assert, createClients, delayToPropogate } from './test-utils' import { Query, JSContentCodec, @@ -1526,3 +1526,13 @@ test('can start conversations without consent proofs', async () => { await delayToPropogate() return true }) + +test('can export logs', async () => { + await createClients(2) + + const logs = await Client.exportNativeLogs() + console.log(logs) + assert(logs.includes('libxmtp'), 'should be able to read libxmtp logs') + + return true +}) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 06feda5d4..1d1c7c10c 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -1,6 +1,7 @@ import ExpoModulesCore import XMTP import LibXMTP +import OSLog extension Conversation { static func cacheKeyForTopic(inboxId: String, topic: String) -> String { @@ -1459,6 +1460,21 @@ public class XMTPModule: Module { } return await client.contacts.isGroupDenied(groupId: groupId) } + + AsyncFunction("exportNativeLogs") { () -> String in + var logOutput = "" + let logStore = try OSLogStore(scope: .currentProcessIdentifier) + let position = logStore.position(timeIntervalSinceLatestBoot: -600) // Last 10 min of logs + let entries = try logStore.getEntries(at: position) + + for entry in entries { + if let logEntry = entry as? OSLogEntryLog { + logOutput.append("\(logEntry.date): \(logEntry.composedMessage)\n") + } + } + + return logOutput + } } // diff --git a/src/index.ts b/src/index.ts index 35fa9e7be..c7eb2b4e3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1149,6 +1149,10 @@ export async function processWelcomeMessage< return new Group(client, JSON.parse(json)) } +export async function exportNativeLogs() { + return XMTPModule.exportNativeLogs() +} + export const emitter = new EventEmitter(XMTPModule ?? NativeModulesProxy.XMTP) interface AuthParams { diff --git a/src/lib/Client.ts b/src/lib/Client.ts index 5f784ce16..d84e0f69a 100644 --- a/src/lib/Client.ts +++ b/src/lib/Client.ts @@ -147,6 +147,10 @@ export class Client< }) } + static async exportNativeLogs() { + return XMTPModule.exportNativeLogs() + } + private static removeAllSubscriptions( createSubscription?: Subscription, enableSubscription?: Subscription,