1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include "iotx_dm_internal.h"
6
7 #if defined(LOG_REPORT_TO_CLOUD) && !defined(DEVICE_MODEL_RAWDATA_SOLO)
8
9 #include "linkkit/dev_model_api.h"
10
11 const char THING_LOG_POST_PARAMS_HEAD[] = "\"%.*s %s %ld ";
12 const char THING_LOG_POST_PARAMS_BODY[] = "%s %ld ";
13 const char THING_LOG_POST_PARAMS_END[] = "%s %ld\",";
14
15 char *g_log_poll = NULL;
16 static char *current_log_pos = NULL;
17
remove_log_poll()18 int remove_log_poll()
19 {
20 if (NULL != g_log_poll) {
21 HAL_Free(g_log_poll);
22 g_log_poll = NULL;
23 current_log_pos = NULL;
24 }
25 return 0;
26 }
27
push_log(const char * input_log,int input_log_size)28 unsigned int push_log(const char *input_log, int input_log_size)
29 {
30 unsigned int len = 0;
31
32 if (NULL == current_log_pos || NULL == input_log || input_log_size <= 0) {
33 dm_log_debug("invalid params");
34 return -1;
35 }
36 memcpy(current_log_pos, input_log, input_log_size);
37 current_log_pos += input_log_size;
38 len = current_log_pos - g_log_poll;
39
40 return len;
41 }
42
add_tail()43 unsigned int add_tail()
44 {
45 const char *tail = "]}";
46 current_log_pos -= 1;
47 return push_log(tail, strlen(tail));
48 }
49
add_log_header()50 void add_log_header()
51 {
52 const char *subprefix =
53 "{\"template\": \"traceContext logContent\",\"contents\":[";
54 int sublen = strlen(subprefix);
55 push_log(subprefix, sublen);
56 }
57
reset_log_poll()58 int reset_log_poll()
59 {
60 if (NULL == g_log_poll) {
61 dm_log_err("log buffer is NULL");
62 return -1;
63 }
64 memset(g_log_poll, 0, LOG_POLL_SIZE);
65 current_log_pos = g_log_poll;
66 add_log_header();
67 return 0;
68 }
69
create_log_poll()70 int create_log_poll()
71 {
72 int ret;
73 remove_log_poll();
74 g_log_poll = HAL_Malloc(LOG_POLL_SIZE);
75 ret = reset_log_poll();
76 return ret;
77 }
78
79 static int switch_status = 0; /* 0 for switch off; 1 for switch on */
80 static unsigned int sample_interval = 5;
81 static unsigned int sample_count = 1000;
82
83 #define MSG_ID_LEN (64)
84 char msg_array[MSG_ID_LEN] = { 0 };
check_target_msg(const char * input,int len)85 int check_target_msg(const char *input, int len)
86 {
87 /* do not upload log when swith is off */
88 if (0 == switch_status) {
89 return -1;
90 }
91 if (NULL == input || len <= 0) {
92 dm_log_err("invalid params");
93 return -1;
94 }
95 return strncmp(input, msg_array, len);
96 }
97
98 static unsigned int msg_num = 0;
99 /* return 0 for success; -1 for failure */
set_target_msg(const char * input,int len)100 int set_target_msg(const char *input, int len)
101 {
102 if (0 == switch_status) {
103 return -1;
104 }
105 if ((msg_num % sample_interval == 0) && (msg_num < sample_count)) {
106 if (NULL == input || len <= 0) {
107 dm_log_err("invalid params");
108 return -1;
109 }
110 strncpy(msg_array, input, len);
111 return 0;
112 }
113 return -1;
114 }
115
parse_msg_id(_IN_ char * payload,_IN_ int payload_len,_OU_ dm_msg_request_payload_t * request)116 void parse_msg_id(_IN_ char *payload, _IN_ int payload_len,
117 _OU_ dm_msg_request_payload_t *request)
118 {
119 lite_cjson_t lite;
120
121 if (payload == NULL || payload_len <= 0 || request == NULL) {
122 return;
123 }
124
125 dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite);
126 dm_utils_json_object_item(&lite, DM_MSG_KEY_ID, strlen(DM_MSG_KEY_ID),
127 cJSON_String, &request->id);
128 }
129
stop_sample()130 int stop_sample()
131 {
132 if (current_log_pos > g_log_poll) {
133 dm_mgr_upstream_thing_log_post(0, NULL, 0, 1);
134 }
135 switch_status = 0;
136 dm_log_info("stop sample");
137 return remove_log_poll();
138 }
139
parse_switch_info(_IN_ char * payload,_IN_ int payload_len)140 void parse_switch_info(_IN_ char *payload, _IN_ int payload_len)
141 {
142 lite_cjson_t lite, lite_sample_count, lite_sample_interval,
143 lite_sample_target;
144 const char *c1 = "Count";
145 const char *c2 = "Interval";
146 const char *c3 = "ProfileTarget";
147 char *sample_target;
148 int sample_target_len;
149 const char *target = "propSet";
150 int ret = -1;
151
152 if (payload == NULL || payload_len <= 0) {
153 return;
154 }
155 dm_utils_json_parse(payload, payload_len, cJSON_Object, &lite);
156 ret = lite_cjson_object_item(&lite, c1, strlen(c1), &lite_sample_count);
157 if (ret < SUCCESS_RETURN) {
158 return;
159 }
160
161 ret = lite_cjson_object_item(&lite, c2, strlen(c2), &lite_sample_interval);
162 if (ret < SUCCESS_RETURN) {
163 return;
164 }
165
166 ret = lite_cjson_object_item(&lite, c3, strlen(c3), &lite_sample_target);
167 if (ret < SUCCESS_RETURN) {
168 return;
169 }
170
171 sample_count = lite_sample_count.value_int;
172 sample_interval = lite_sample_interval.value_int;
173 sample_target = lite_sample_target.value;
174 sample_target_len = lite_sample_target.value_length;
175 dm_log_info("switch count is %d, interval is %d, target is %.*s\n",
176 sample_count, sample_interval, sample_target_len,
177 sample_target);
178 /* if the target is not property set, return */
179 if (0 != strncmp(sample_target, target, sample_target_len)) {
180 dm_log_info("target is not propSet, return\n");
181 return;
182 }
183 if (sample_interval <= 0) {
184 dm_log_err("invalid sample interval\n");
185 return;
186 }
187 msg_num = 0;
188 /* when it switch off, force upload the remaining log */
189 if (0 == sample_count) {
190 ret = stop_sample();
191 } else {
192 switch_status = 1;
193 ret = create_log_poll();
194 }
195
196 dm_log_info("log switch run status is %d\n", ret);
197 }
198
199 REPORT_STATE g_report_status = READY;
200
send_permance_info(char * input,int input_len,char * comments,int report_format)201 void send_permance_info(char *input, int input_len, char *comments,
202 int report_format)
203 {
204 #define LOCAL_POST_LEN (150)
205 char data[LOCAL_POST_LEN] = { 0 };
206 const char *format = NULL;
207 if (0 == switch_status) {
208 return;
209 }
210
211 switch (report_format) {
212 case 0:
213 if (NULL == input || input_len <= 0) {
214 dm_log_err("invalid params");
215 return;
216 }
217 format = THING_LOG_POST_PARAMS_HEAD;
218 HAL_Snprintf(data, sizeof(data), format, input_len, input, comments,
219 (long)HAL_UptimeMs());
220 break;
221 case 1:
222 format = THING_LOG_POST_PARAMS_BODY;
223 HAL_Snprintf(data, sizeof(data), format, comments,
224 (long)HAL_UptimeMs());
225 break;
226 case 2:
227 format = THING_LOG_POST_PARAMS_END;
228 HAL_Snprintf(data, sizeof(data), format, comments,
229 (long)HAL_UptimeMs());
230 g_report_status = DONE;
231 break;
232 default:
233 return;
234 }
235 iotx_dm_log_post(0, data, strlen((const char *)data));
236 if (2 == report_format) {
237 g_report_status = READY;
238 }
239 }
240
get_msgid(char * payload,int is_cloud)241 void get_msgid(char *payload, int is_cloud)
242 {
243 const char *interest = "\"method\":\"thing.service.property.set";
244 char *found;
245 dm_msg_request_payload_t request;
246 if (0 == switch_status || NULL == payload) {
247 return;
248 }
249
250 found = strstr(payload, interest);
251 if (NULL == found) {
252 return;
253 }
254 found = strstr(payload, "{");
255 if (NULL == found) {
256 return;
257 }
258 msg_num++;
259 parse_msg_id(found, strlen(found), &request);
260 if (RUNNING == g_report_status) {
261 dm_log_info("current working on a sample, return");
262 return;
263 }
264
265 if (sample_count <= msg_num) {
266 stop_sample();
267 return;
268 }
269
270 /* if it does not meet the sample conditions, do NOT take sample */
271 if (SUCCESS_RETURN !=
272 set_target_msg(request.id.value, request.id.value_length)) {
273 return;
274 }
275
276 g_report_status = RUNNING;
277
278 if (1 == is_cloud) {
279 send_permance_info(request.id.value, request.id.value_length, "1_cloud",
280 0);
281 } else if (0 == is_cloud) {
282 send_permance_info(request.id.value, request.id.value_length, "1_alcs",
283 0);
284 }
285 }
286 #endif
287