log_mqtt.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * Tencent is pleased to support the open source community by making IoT Hub available.
  3. * Copyright (C) 2018-2020 THL A29 Limited, a Tencent company. All rights reserved.
  4. * Licensed under the MIT License (the "License"); you may not use this file except in
  5. * compliance with the License. You may obtain a copy of the License at
  6. * http://opensource.org/licenses/MIT
  7. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  8. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  9. * either express or implied. See the License for the specific language governing permissions and
  10. * limitations under the License.
  11. *
  12. */
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16. #include "config.h"
  17. #ifdef LOG_UPLOAD
  18. #include <string.h>
  19. #include "lite-utils.h"
  20. #include "log_upload.h"
  21. #include "mqtt_client.h"
  22. #include "qcloud_iot_device.h"
  23. typedef struct _log_mqtt_state {
  24. bool topic_sub_ok;
  25. bool result_recv_ok;
  26. int log_level;
  27. } LogMQTTState;
  28. static LogMQTTState sg_log_state = {.topic_sub_ok = false, .result_recv_ok = false, .log_level = eLOG_ERROR};
  29. static bool _get_json_log_level(char *json, int32_t *res)
  30. {
  31. char *v = LITE_json_value_of("log_level", json);
  32. if (v == NULL) {
  33. Log_e("Invalid log level from JSON: %s", json);
  34. return false;
  35. }
  36. if (LITE_get_int32(res, v) != QCLOUD_RET_SUCCESS) {
  37. Log_e("Invalid log level from JSON: %s", json);
  38. HAL_Free(v);
  39. return false;
  40. }
  41. HAL_Free(v);
  42. return true;
  43. }
  44. static void _log_level_sub_cb(void *pClient, MQTTMessage *message, void *pUserData)
  45. {
  46. #define LOG_JSON_LENGTH 128
  47. char json_buf[LOG_JSON_LENGTH] = {0};
  48. int32_t json_buf_len = 0;
  49. if (message == NULL) {
  50. return;
  51. }
  52. LogMQTTState *state = (LogMQTTState *)pUserData;
  53. json_buf_len = Min(LOG_JSON_LENGTH - 1, message->payload_len);
  54. memcpy(json_buf, message->payload, json_buf_len);
  55. json_buf[json_buf_len] = '\0'; // json_parse relies on a string
  56. Log_d("Recv Msg Topic:%s, payload:%s", message->ptopic, json_buf);
  57. int32_t log_level;
  58. if (!_get_json_log_level(json_buf, &log_level)) {
  59. return;
  60. }
  61. switch (log_level) {
  62. case eLOG_DISABLE:
  63. Log_w("Upload log level change to: %d", log_level);
  64. clear_upload_buffer();
  65. set_log_upload_in_comm_err(true);
  66. IOT_Log_Set_Upload_Level(eLOG_ERROR);
  67. break;
  68. case eLOG_ERROR:
  69. case eLOG_WARN:
  70. case eLOG_INFO:
  71. case eLOG_DEBUG:
  72. if (log_level < IOT_Log_Get_Upload_Level())
  73. clear_upload_buffer();
  74. IOT_Log_Set_Upload_Level((LOG_LEVEL)log_level);
  75. Log_w("Upload log level change to: %d", log_level);
  76. set_log_upload_in_comm_err(false);
  77. break;
  78. default:
  79. Log_e("Invalid log level: %d", log_level);
  80. break;
  81. }
  82. state->log_level = log_level;
  83. state->result_recv_ok = true;
  84. }
  85. static void _log_mqtt_sub_event_handler(void *pclient, MQTTEventType event_type, void *pUserData)
  86. {
  87. LogMQTTState *state = (LogMQTTState *)pUserData;
  88. switch (event_type) {
  89. case MQTT_EVENT_SUBCRIBE_SUCCESS:
  90. Log_d("mqtt log topic subscribe success");
  91. state->topic_sub_ok = true;
  92. break;
  93. case MQTT_EVENT_SUBCRIBE_TIMEOUT:
  94. Log_i("mqtt log topic subscribe timeout");
  95. state->topic_sub_ok = false;
  96. break;
  97. case MQTT_EVENT_SUBCRIBE_NACK:
  98. Log_i("mqtt log topic subscribe NACK");
  99. state->topic_sub_ok = false;
  100. break;
  101. case MQTT_EVENT_UNSUBSCRIBE:
  102. Log_i("mqtt log topic has been unsubscribed");
  103. state->topic_sub_ok = false;
  104. ;
  105. break;
  106. case MQTT_EVENT_CLIENT_DESTROY:
  107. Log_i("mqtt client has been destroyed");
  108. state->topic_sub_ok = false;
  109. ;
  110. break;
  111. default:
  112. return;
  113. }
  114. }
  115. static int _iot_log_level_get_publish(void *pClient, DeviceInfo *dev_info)
  116. {
  117. POINTER_SANITY_CHECK(pClient, QCLOUD_ERR_INVAL);
  118. static unsigned int sg_client_token = 1;
  119. Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)pClient;
  120. char topic_name[128] = {0};
  121. char payload_content[128] = {0};
  122. HAL_Snprintf(topic_name, sizeof(topic_name), "$log/operation/%s/%s", dev_info->product_id, dev_info->device_name);
  123. HAL_Snprintf(payload_content, sizeof(payload_content),
  124. "{\"type\": \"get_log_level\", "
  125. "\"clientToken\": \"%s-%u\"}",
  126. dev_info->product_id, sg_client_token++);
  127. PublishParams pub_params = DEFAULT_PUB_PARAMS;
  128. pub_params.qos = QOS0;
  129. pub_params.payload = payload_content;
  130. pub_params.payload_len = strlen(payload_content);
  131. return IOT_MQTT_Publish(mqtt_client, topic_name, &pub_params);
  132. }
  133. static int _log_topic_subscribe(void *client, DeviceInfo *dev_info)
  134. {
  135. /* subscribe the log topic: "$log/operation/result/${productId}/${deviceName}" */
  136. char topic_name[128] = {0};
  137. int size = HAL_Snprintf(topic_name, sizeof(topic_name), "$log/operation/result/%s/%s", dev_info->product_id,
  138. dev_info->device_name);
  139. if (size < 0 || size > sizeof(topic_name) - 1) {
  140. Log_e("topic content buf not enough! content size:%d buf size:%d", size, (int)sizeof(topic_name));
  141. return QCLOUD_ERR_FAILURE;
  142. }
  143. SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
  144. sub_params.on_message_handler = _log_level_sub_cb;
  145. sub_params.on_sub_event_handler = _log_mqtt_sub_event_handler;
  146. sub_params.user_data = (void *)&sg_log_state;
  147. sub_params.qos = QOS0;
  148. return IOT_MQTT_Subscribe(client, topic_name, &sub_params);
  149. }
  150. int qcloud_get_log_level(int *log_level)
  151. {
  152. #define SUB_RETRY_TIMES 3
  153. #define SYNC_TIMES 20
  154. int ret = 0;
  155. int cntSub = 0;
  156. int cntRev = 0;
  157. Qcloud_IoT_Client *mqtt_client = (Qcloud_IoT_Client *)get_log_mqtt_client();
  158. DeviceInfo *dev_info = (DeviceInfo *)get_log_dev_info();
  159. POINTER_SANITY_CHECK(mqtt_client, QCLOUD_ERR_INVAL);
  160. LogMQTTState *pLogState = &sg_log_state;
  161. // subscribe log topic: $log/operation/get/${productid}/${devicename}
  162. // skip this if the subscription is done and valid
  163. if (!pLogState->topic_sub_ok) {
  164. for (cntSub = 0; cntSub < SUB_RETRY_TIMES; cntSub++) {
  165. ret = _log_topic_subscribe(mqtt_client, dev_info);
  166. if (ret < 0) {
  167. Log_w("qcloud_log_topic_subscribe failed: %d, cnt: %d", ret, cntSub);
  168. continue;
  169. }
  170. /* wait for sub ack */
  171. ret = qcloud_iot_mqtt_yield_mt(mqtt_client, 100);
  172. if (pLogState->topic_sub_ok) {
  173. break;
  174. }
  175. }
  176. }
  177. // return failure if subscribe failed
  178. if (!pLogState->topic_sub_ok) {
  179. Log_e("Subscribe log topic failed!");
  180. return QCLOUD_ERR_FAILURE;
  181. }
  182. pLogState->result_recv_ok = false;
  183. // publish msg to get log level
  184. ret = _iot_log_level_get_publish(mqtt_client, dev_info);
  185. if (ret < 0) {
  186. Log_e("client publish log topic failed :%d", ret);
  187. return ret;
  188. }
  189. do {
  190. ret = qcloud_iot_mqtt_yield_mt(mqtt_client, 100);
  191. cntRev++;
  192. } while (!ret && !pLogState->result_recv_ok && cntRev < SYNC_TIMES);
  193. *log_level = pLogState->log_level;
  194. if (pLogState->result_recv_ok)
  195. ret = QCLOUD_RET_SUCCESS;
  196. else
  197. ret = QCLOUD_ERR_FAILURE;
  198. return ret;
  199. #undef SUB_RETRY_TIMES
  200. }
  201. #endif
  202. #ifdef __cplusplus
  203. }
  204. #endif