3333#include < fbjni/ByteBuffer.h>
3434#include < fbjni/fbjni.h>
3535
36+ using namespace executorch ::extension;
37+ using namespace torch ::executor;
38+
3639#ifdef __ANDROID__
3740#include < android/log.h>
41+ #include < mutex>
42+ #include < stringstream>
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+ }
3875
3976// For Android, write to logcat
4077void et_pal_emit_log_message (
@@ -45,6 +82,22 @@ void et_pal_emit_log_message(
4582 size_t line,
4683 const char * message,
4784 size_t length) {
85+
86+ std::lock_guard<std::mutex> guard (log_buffer_mutex_);
87+
88+ while (log_buffer_.size () >= log_buffer_length) {
89+ log_buffer_.erase (log_buffer_.front ());
90+ }
91+
92+ log_buffer_.emplace_back (
93+ timestamp,
94+ level,
95+ filename,
96+ function,
97+ line,
98+ message,
99+ length);
100+
48101 int android_log_level = ANDROID_LOG_UNKNOWN;
49102 if (level == ' D' ) {
50103 android_log_level = ANDROID_LOG_DEBUG;
@@ -60,9 +113,6 @@ void et_pal_emit_log_message(
60113}
61114#endif
62115
63- using namespace executorch ::extension;
64- using namespace torch ::executor;
65-
66116namespace executorch ::extension {
67117class TensorHybrid : public facebook ::jni::HybridClass<TensorHybrid> {
68118 public:
@@ -391,12 +441,42 @@ class ExecuTorchJni : public facebook::jni::HybridClass<ExecuTorchJni> {
391441 return jresult;
392442 }
393443
444+ facebook::jni::local_ref<JArrayClass<JString>> readLogBuffer () {
445+ #ifdef __ANDROID__
446+ std::lock_guard<std::mutex> guard (log_buffer_mutex_);
447+
448+ const auto size = log_buffer_.size ();
449+ local_ref<JArrayClass<JString>> ret = JArrayClass<JString>::newArray (size);
450+
451+ for (auto i = 0u ; i < size; i++) {
452+ const auto & entry = log_buffer_[i];
453+ // Format the log entry as "[TIMESTAMP FUNCTION FILE:LINE] LEVEL MESSAGE".
454+ std::stringstream ss;
455+ ss
456+ << " [" << entry.timestamp << " " << entry.function
457+ << " " << entry.filename << " :" << entry.line << " ] "
458+ << entry.level << " " << entry.message ;
459+
460+ auto jstr_message = make_jstring (ss.str ().c_str ());
461+ ret->setElement (i, *jstr_message);
462+ }
463+
464+ return ret;
465+ #else
466+ return JArrayClass<String>::newArray (0 );
467+ #endif
468+ }
469+
394470 static void registerNatives () {
395471 registerHybrid ({
396472 makeNativeMethod (" initHybrid" , ExecuTorchJni::initHybrid),
397473 makeNativeMethod (" forward" , ExecuTorchJni::forward),
398474 makeNativeMethod (" execute" , ExecuTorchJni::execute),
399475 makeNativeMethod (" loadMethod" , ExecuTorchJni::load_method),
476+
477+ #ifdef __ANDROID__
478+ makeNativeMethod (" readLogBuffer" , ExecuTorchJni::readLogBuffer),
479+ #endif
400480 });
401481 }
402482};
0 commit comments