loggerjnicallback.cc 8.8 KB

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