loggerjnicallback.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // This file implements the callback "bridge" between Java and C++ for
  7. // ROCKSDB_NAMESPACE::Logger.
  8. #include "rocksjni/loggerjnicallback.h"
  9. #include <cstdarg>
  10. #include <cstdio>
  11. #include "include/org_rocksdb_Logger.h"
  12. #include "rocksjni/cplusplus_to_java_convert.h"
  13. #include "rocksjni/portal.h"
  14. namespace ROCKSDB_NAMESPACE {
  15. LoggerJniCallback::LoggerJniCallback(JNIEnv* env, jobject jlogger)
  16. : JniCallback(env, jlogger) {
  17. m_jLogMethodId = LoggerJni::getLogMethodId(env);
  18. if (m_jLogMethodId == nullptr) {
  19. // exception thrown: NoSuchMethodException or OutOfMemoryError
  20. return;
  21. }
  22. jobject jdebug_level = InfoLogLevelJni::DEBUG_LEVEL(env);
  23. if (jdebug_level == nullptr) {
  24. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  25. // or OutOfMemoryError
  26. return;
  27. }
  28. m_jdebug_level = env->NewGlobalRef(jdebug_level);
  29. if (m_jdebug_level == nullptr) {
  30. // exception thrown: OutOfMemoryError
  31. return;
  32. }
  33. jobject jinfo_level = InfoLogLevelJni::INFO_LEVEL(env);
  34. if (jinfo_level == nullptr) {
  35. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  36. // or OutOfMemoryError
  37. return;
  38. }
  39. m_jinfo_level = env->NewGlobalRef(jinfo_level);
  40. if (m_jinfo_level == nullptr) {
  41. // exception thrown: OutOfMemoryError
  42. return;
  43. }
  44. jobject jwarn_level = InfoLogLevelJni::WARN_LEVEL(env);
  45. if (jwarn_level == nullptr) {
  46. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  47. // or OutOfMemoryError
  48. return;
  49. }
  50. m_jwarn_level = env->NewGlobalRef(jwarn_level);
  51. if (m_jwarn_level == nullptr) {
  52. // exception thrown: OutOfMemoryError
  53. return;
  54. }
  55. jobject jerror_level = InfoLogLevelJni::ERROR_LEVEL(env);
  56. if (jerror_level == nullptr) {
  57. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  58. // or OutOfMemoryError
  59. return;
  60. }
  61. m_jerror_level = env->NewGlobalRef(jerror_level);
  62. if (m_jerror_level == nullptr) {
  63. // exception thrown: OutOfMemoryError
  64. return;
  65. }
  66. jobject jfatal_level = InfoLogLevelJni::FATAL_LEVEL(env);
  67. if (jfatal_level == nullptr) {
  68. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  69. // or OutOfMemoryError
  70. return;
  71. }
  72. m_jfatal_level = env->NewGlobalRef(jfatal_level);
  73. if (m_jfatal_level == nullptr) {
  74. // exception thrown: OutOfMemoryError
  75. return;
  76. }
  77. jobject jheader_level = InfoLogLevelJni::HEADER_LEVEL(env);
  78. if (jheader_level == nullptr) {
  79. // exception thrown: NoSuchFieldError, ExceptionInInitializerError
  80. // or OutOfMemoryError
  81. return;
  82. }
  83. m_jheader_level = env->NewGlobalRef(jheader_level);
  84. if (m_jheader_level == nullptr) {
  85. // exception thrown: OutOfMemoryError
  86. return;
  87. }
  88. }
  89. void LoggerJniCallback::Logv(const char* /*format*/, va_list /*ap*/) {
  90. // We implement this method because it is virtual but we don't
  91. // use it because we need to know about the log level.
  92. }
  93. void LoggerJniCallback::Logv(const InfoLogLevel log_level, const char* format,
  94. va_list ap) {
  95. if (GetInfoLogLevel() <= log_level) {
  96. // determine InfoLogLevel java enum instance
  97. jobject jlog_level;
  98. switch (log_level) {
  99. case ROCKSDB_NAMESPACE::InfoLogLevel::DEBUG_LEVEL:
  100. jlog_level = m_jdebug_level;
  101. break;
  102. case ROCKSDB_NAMESPACE::InfoLogLevel::INFO_LEVEL:
  103. jlog_level = m_jinfo_level;
  104. break;
  105. case ROCKSDB_NAMESPACE::InfoLogLevel::WARN_LEVEL:
  106. jlog_level = m_jwarn_level;
  107. break;
  108. case ROCKSDB_NAMESPACE::InfoLogLevel::ERROR_LEVEL:
  109. jlog_level = m_jerror_level;
  110. break;
  111. case ROCKSDB_NAMESPACE::InfoLogLevel::FATAL_LEVEL:
  112. jlog_level = m_jfatal_level;
  113. break;
  114. case ROCKSDB_NAMESPACE::InfoLogLevel::HEADER_LEVEL:
  115. jlog_level = m_jheader_level;
  116. break;
  117. default:
  118. jlog_level = m_jfatal_level;
  119. break;
  120. }
  121. assert(format != nullptr);
  122. const std::unique_ptr<char[]> msg = format_str(format, ap);
  123. // pass msg to java callback handler
  124. jboolean attached_thread = JNI_FALSE;
  125. JNIEnv* env = getJniEnv(&attached_thread);
  126. assert(env != nullptr);
  127. jstring jmsg = env->NewStringUTF(msg.get());
  128. if (jmsg == nullptr) {
  129. // unable to construct string
  130. if (env->ExceptionCheck()) {
  131. env->ExceptionDescribe(); // print out exception to stderr
  132. }
  133. releaseJniEnv(attached_thread);
  134. return;
  135. }
  136. if (env->ExceptionCheck()) {
  137. // exception thrown: OutOfMemoryError
  138. env->ExceptionDescribe(); // print out exception to stderr
  139. env->DeleteLocalRef(jmsg);
  140. releaseJniEnv(attached_thread);
  141. return;
  142. }
  143. env->CallVoidMethod(m_jcallback_obj, m_jLogMethodId, jlog_level, jmsg);
  144. if (env->ExceptionCheck()) {
  145. // exception thrown
  146. env->ExceptionDescribe(); // print out exception to stderr
  147. env->DeleteLocalRef(jmsg);
  148. releaseJniEnv(attached_thread);
  149. return;
  150. }
  151. env->DeleteLocalRef(jmsg);
  152. releaseJniEnv(attached_thread);
  153. }
  154. }
  155. std::unique_ptr<char[]> LoggerJniCallback::format_str(const char* format,
  156. va_list ap) const {
  157. va_list ap_copy;
  158. va_copy(ap_copy, ap);
  159. const size_t required =
  160. vsnprintf(nullptr, 0, format, ap_copy) + 1; // Extra space for '\0'
  161. va_end(ap_copy);
  162. std::unique_ptr<char[]> buf(new char[required]);
  163. va_copy(ap_copy, ap);
  164. vsnprintf(buf.get(), required, format, ap_copy);
  165. va_end(ap_copy);
  166. return buf;
  167. }
  168. LoggerJniCallback::~LoggerJniCallback() {
  169. jboolean attached_thread = JNI_FALSE;
  170. JNIEnv* env = getJniEnv(&attached_thread);
  171. assert(env != nullptr);
  172. if (m_jdebug_level != nullptr) {
  173. env->DeleteGlobalRef(m_jdebug_level);
  174. }
  175. if (m_jinfo_level != nullptr) {
  176. env->DeleteGlobalRef(m_jinfo_level);
  177. }
  178. if (m_jwarn_level != nullptr) {
  179. env->DeleteGlobalRef(m_jwarn_level);
  180. }
  181. if (m_jerror_level != nullptr) {
  182. env->DeleteGlobalRef(m_jerror_level);
  183. }
  184. if (m_jfatal_level != nullptr) {
  185. env->DeleteGlobalRef(m_jfatal_level);
  186. }
  187. if (m_jheader_level != nullptr) {
  188. env->DeleteGlobalRef(m_jheader_level);
  189. }
  190. releaseJniEnv(attached_thread);
  191. }
  192. } // namespace ROCKSDB_NAMESPACE
  193. /*
  194. * Class: org_rocksdb_Logger
  195. * Method: newLogger
  196. * Signature: (J)J
  197. */
  198. jlong Java_org_rocksdb_Logger_newLogger(JNIEnv* env, jobject jobj,
  199. jlong jlog_level) {
  200. auto* sptr_logger = new std::shared_ptr<ROCKSDB_NAMESPACE::LoggerJniCallback>(
  201. new ROCKSDB_NAMESPACE::LoggerJniCallback(env, jobj));
  202. auto log_level = static_cast<ROCKSDB_NAMESPACE::InfoLogLevel>(jlog_level);
  203. sptr_logger->get()->SetInfoLogLevel(log_level);
  204. return GET_CPLUSPLUS_POINTER(sptr_logger);
  205. }
  206. /*
  207. * Class: org_rocksdb_Logger
  208. * Method: setInfoLogLevel
  209. * Signature: (JB)V
  210. */
  211. void Java_org_rocksdb_Logger_setInfoLogLevel(JNIEnv* /*env*/, jobject /*jobj*/,
  212. jlong jhandle, jbyte jlog_level) {
  213. auto* handle =
  214. reinterpret_cast<std::shared_ptr<ROCKSDB_NAMESPACE::LoggerJniCallback>*>(
  215. jhandle);
  216. handle->get()->SetInfoLogLevel(
  217. static_cast<ROCKSDB_NAMESPACE::InfoLogLevel>(jlog_level));
  218. }
  219. /*
  220. * Class: org_rocksdb_Logger
  221. * Method: infoLogLevel
  222. * Signature: (J)B
  223. */
  224. jbyte Java_org_rocksdb_Logger_infoLogLevel(JNIEnv* /*env*/, jobject /*jobj*/,
  225. jlong jhandle) {
  226. auto* handle =
  227. reinterpret_cast<std::shared_ptr<ROCKSDB_NAMESPACE::LoggerJniCallback>*>(
  228. jhandle);
  229. return static_cast<jbyte>(handle->get()->GetInfoLogLevel());
  230. }
  231. /*
  232. * Class: org_rocksdb_Logger
  233. * Method: disposeInternal
  234. * Signature: (J)V
  235. */
  236. void Java_org_rocksdb_Logger_disposeInternal(JNIEnv* /*env*/, jobject /*jobj*/,
  237. jlong jhandle) {
  238. auto* handle =
  239. reinterpret_cast<std::shared_ptr<ROCKSDB_NAMESPACE::LoggerJniCallback>*>(
  240. jhandle);
  241. delete handle; // delete std::shared_ptr
  242. }