33
33
#include < fbjni/ByteBuffer.h>
34
34
#include < fbjni/fbjni.h>
35
35
36
+ using namespace executorch ::extension;
37
+ using namespace torch ::executor;
38
+
36
39
#ifdef __ANDROID__
37
40
#include < android/log.h>
41
+ #include < mutex>
42
+ #include < sstream>
43
+
44
+ // Number of entries to store in the in-memory log buffer.
45
+ const size_t log_buffer_length = 16 ;
46
+
47
+ struct log_entry {
48
+ et_timestamp_t timestamp;
49
+ et_pal_log_level_t level;
50
+ std::string filename;
51
+ std::string function;
52
+ size_t line;
53
+ std::string message;
54
+
55
+ log_entry (
56
+ et_timestamp_t timestamp,
57
+ et_pal_log_level_t level,
58
+ const char * filename,
59
+ const char * function,
60
+ size_t line,
61
+ const char * message,
62
+ size_t length)
63
+ : timestamp(timestamp),
64
+ level (level),
65
+ filename(filename),
66
+ function(function),
67
+ line(line),
68
+ message(message, length) {}
69
+ };
70
+
71
+ namespace {
72
+ std::vector<log_entry> log_buffer_;
73
+ std::mutex log_buffer_mutex_;
74
+ } // namespace
38
75
39
76
// For Android, write to logcat
40
77
void et_pal_emit_log_message (
@@ -45,6 +82,15 @@ void et_pal_emit_log_message(
45
82
size_t line,
46
83
const char * message,
47
84
size_t length) {
85
+ std::lock_guard<std::mutex> guard (log_buffer_mutex_);
86
+
87
+ while (log_buffer_.size () >= log_buffer_length) {
88
+ log_buffer_.erase (log_buffer_.begin ());
89
+ }
90
+
91
+ log_buffer_.emplace_back (
92
+ timestamp, level, filename, function, line, message, length);
93
+
48
94
int android_log_level = ANDROID_LOG_UNKNOWN;
49
95
if (level == ' D' ) {
50
96
android_log_level = ANDROID_LOG_DEBUG;
@@ -60,9 +106,6 @@ void et_pal_emit_log_message(
60
106
}
61
107
#endif
62
108
63
- using namespace executorch ::extension;
64
- using namespace torch ::executor;
65
-
66
109
namespace executorch ::extension {
67
110
class TensorHybrid : public facebook ::jni::HybridClass<TensorHybrid> {
68
111
public:
@@ -391,12 +434,44 @@ class ExecuTorchJni : public facebook::jni::HybridClass<ExecuTorchJni> {
391
434
return jresult;
392
435
}
393
436
437
+ facebook::jni::local_ref<facebook::jni::JArrayClass<jstring>>
438
+ readLogBuffer () {
439
+ #ifdef __ANDROID__
440
+ std::lock_guard<std::mutex> guard (log_buffer_mutex_);
441
+
442
+ const auto size = log_buffer_.size ();
443
+ facebook::jni::local_ref<facebook::jni::JArrayClass<jstring>> ret =
444
+ facebook::jni::JArrayClass<jstring>::newArray (size);
445
+
446
+ for (auto i = 0u ; i < size; i++) {
447
+ const auto & entry = log_buffer_[i];
448
+ // Format the log entry as "[TIMESTAMP FUNCTION FILE:LINE] LEVEL MESSAGE".
449
+ std::stringstream ss;
450
+ ss << " [" << entry.timestamp << " " << entry.function << " "
451
+ << entry.filename << " :" << entry.line << " ] "
452
+ << static_cast <char >(entry.level ) << " " << entry.message ;
453
+
454
+ facebook::jni::local_ref<facebook::jni::JString> jstr_message =
455
+ facebook::jni::make_jstring (ss.str ().c_str ());
456
+ (*ret)[i] = jstr_message;
457
+ }
458
+
459
+ return ret;
460
+ #else
461
+ return facebook::jni::JArrayClass<String>::newArray (0 );
462
+ #endif
463
+ }
464
+
394
465
static void registerNatives () {
395
466
registerHybrid ({
396
467
makeNativeMethod (" initHybrid" , ExecuTorchJni::initHybrid),
397
468
makeNativeMethod (" forward" , ExecuTorchJni::forward),
398
469
makeNativeMethod (" execute" , ExecuTorchJni::execute),
399
470
makeNativeMethod (" loadMethod" , ExecuTorchJni::load_method),
471
+
472
+ #ifdef __ANDROID__
473
+ makeNativeMethod (" readLogBuffer" , ExecuTorchJni::readLogBuffer),
474
+ #endif
400
475
});
401
476
}
402
477
};
0 commit comments