void HeapScan() { ListElement* current = NULL; Log(LOG_INFO, Messages_get(101), state.current_size); while (ListNextElement(&heap, ¤t)) { storageElement* s = (storageElement*)(current->content); Log(LOG_INFO, Messages_get(102), s->size, s->line, s->file, s->ptr); Log(LOG_INFO, Messages_get(103), (10 > s->size) ? s->size : 10, s->ptr); } Log(LOG_INFO, Messages_get(104)); }
/** * Log a message. If possible, all messages should be indexed by message number, and * the use of the format string should be minimized or negated altogether. If format is * provided, the message number is only used as a message label. * @param log_level the log level of the message * @param msgno the id of the message to use if the format string is NULL * @param aFormat the printf format string to be used if the message id does not exist * @param ... the printf inserts */ void Log(int log_level, int msgno, char* format, ...) { char* temp = NULL; static char msg_buf[512]; if (log_level >= trace_settings.trace_level) { va_list args; if (format == NULL && (temp = Messages_get(msgno, log_level)) != NULL) format = temp; va_start(args, format); vsnprintf(msg_buf, sizeof(msg_buf), format, args); Log_trace(log_level, msg_buf); va_end(args); } /*if (log_level >= LOG_ERROR) { char* filename = NULL; Log_recordFFDC(&msg_buf[7]); } if (log_level == LOG_FATAL) exit(-1);*/ }
static char* Log_formatTraceEntry(traceEntry* cur_entry) { struct tm *timeinfo; int buf_pos = 31; #if defined(GETTIMEOFDAY) timeinfo = localtime(&cur_entry->ts.tv_sec); #else timeinfo = localtime(&cur_entry->ts.time); #endif strftime(&msg_buf[7], 80, "%Y%m%d %H%M%S ", timeinfo); #if defined(GETTIMEOFDAY) sprintf(&msg_buf[22], ".%.3lu ", cur_entry->ts.tv_usec / 1000L); #else sprintf(&msg_buf[22], ".%.3hu ", cur_entry->ts.millitm); #endif buf_pos = 27; sprintf(msg_buf, "(%.4d)", cur_entry->sametime_count); msg_buf[6] = ' '; if (cur_entry->has_rc == 2) strncpy(&msg_buf[buf_pos], cur_entry->name, sizeof(msg_buf)-buf_pos); else { char* format = Messages_get(cur_entry->number, cur_entry->level); if (cur_entry->has_rc == 1) snprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, format, cur_entry->thread_id, cur_entry->depth, "", cur_entry->depth, cur_entry->name, cur_entry->line, cur_entry->rc); else snprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, format, cur_entry->thread_id, cur_entry->depth, "", cur_entry->depth, cur_entry->name, cur_entry->line); } return msg_buf; }
/** * Log a message. If possible, all messages should be indexed by message number, and * the use of the format string should be minimized or negated altogether. If format is * provided, the message number is only used as a message label. * @param log_level the log level of the message * @param msgno the id of the message to use if the format string is NULL * @param aFormat the printf format string to be used if the message id does not exist * @param ... the printf inserts */ void Log(int log_level, int msgno, char* format, ...) { if (log_level >= trace_settings.trace_level) { char* temp = NULL; static char msg_buf[512]; va_list args; /* we're using a static character buffer, so we need to make sure only one thread uses it at a time */ Thread_lock_mutex(log_mutex); if (format == NULL && (temp = Messages_get(msgno, log_level)) != NULL) format = temp; va_start(args, format); vsnprintf(msg_buf, sizeof(msg_buf), format, args); Log_trace(log_level, msg_buf); va_end(args); Thread_unlock_mutex(log_mutex); } /*if (log_level >= LOG_ERROR) { char* filename = NULL; Log_recordFFDC(&msg_buf[7]); } */ }
void Heap_terminate() { Log(LOG_INFO, "Maximum heap use was %d bytes\n", state.max_size); if (state.current_size > 0) { Log(LOG_ERROR, Messages_get(106)); HeapScan(); } }
void myfree(char* file, int line, void* p) { ListElement* e = ListFindItem(&heap, p, ptrCompare); if (e == NULL) Log(LOG_ERROR, Messages_get(99), file, line); else { storageElement* s = (storageElement*)(heap.current->content); //Log(LOG_DEBUG, "Freeing %d bytes in heap at file %s line %d, heap use now %d bytes\n", s->size, file, line, state.current_size); free(s->file); state.current_size -= s->size; ListRemoveCurrentItem(&heap); } free(p); }
void *myrealloc(char* file, int line, void* p, size_t size) { void* rc = NULL; ListElement* e = ListFindItem(&heap, p, ptrCompare); if (e == NULL) Log(LOG_ERROR, Messages_get(100), file, line); else { storageElement* s = (storageElement*)(heap.current->content); state.current_size += size - s->size; if (state.current_size > state.max_size) state.max_size = state.current_size; rc = s->ptr = realloc(s->ptr, size); s->size = size; s->file = realloc(s->file, strlen(file)+1); strcpy(s->file, file); s->line = line; } return rc; }
/** * Record First Failure Data Capture information for problem determination. * @param symptoms - a symptom string to write along with the rest of the info * @return FFDC filename */ char* Broker_recordFFDC(char* symptoms) { static char filename[160]; struct tm *timeinfo; #if defined(GETTIMEOFDAY) struct timeval ts; #else struct timeb ts; #endif FILE* file = NULL; char* ptr = filename; int mem_leak = 0; filename[0] = '\0'; if (BrokerState.ffdc_location && strcmp(BrokerState.ffdc_location, "off") == 0) { if (segv_flag) printf("%s\n", Messages_get(48, LOG_WARNING)); else Log(LOG_WARNING, 48, NULL); goto exit; } if (BrokerState.ffdc_location) strcpy(filename, BrokerState.ffdc_location); else if (BrokerState.persistence_location) strcpy(filename, BrokerState.persistence_location); ptr += strlen(filename); #if defined(GETTIMEOFDAY) gettimeofday(&ts, NULL); timeinfo = localtime(&ts.tv_sec); #else ftime(&ts); timeinfo = localtime(&ts.time); #endif strftime(ptr, 80, "FFDC.CWNAN.%Y%m%d.%H%M%S.", timeinfo); #if defined(GETTIMEOFDAY) sprintf(&ptr[26], ".%.3ld.dmp", ts.tv_usec / 1000L); #else sprintf(&ptr[26], ".%.3u.dmp", ts.millitm); #endif if ((file = fopen(filename, "wb")) != NULL) { fprintf(file, "========== Start FFDC ==========\n"); fprintf(file, "Filename :- %s\n", filename); fprintf(file, "Product :- %s\n", PRODUCT_NAME); fprintf(file, "Version :- %s\n", BrokerState.version); fprintf(file, "Build :- %s\n", BrokerState.timestamp); fprintf(file, "Date/Time :- %s", asctime(timeinfo)); fprintf(file, "Reason :- %s\n\n", symptoms); /* potential additions: * os info (uname, getWindowsVersion) * environment variables */ fclose(file); } StackTrace_dumpStack(filename); if (strstr(symptoms, "memory leak")) { if ((file = fopen(filename, "ab")) != NULL) { Heap_scan(file); fclose(file); } mem_leak = 1; } else { Log_dumpTrace(filename); Broker_dumpHeap(filename); } if ((file = fopen(filename, "ab")) != NULL) { fprintf(file, "========== End FFDC ==========\n"); fclose(file); } if (segv_flag || mem_leak) printf("First Failure Data Capture (FFDC) information written to file %s\n", filename); exit: return filename; }
/** * Main broker startup function * @param argc number of elements of argv * @param argv command line strings * @return system return code */ int main(int argc, char* argv[]) { int rc = 0; #define BUILD_TIMESTAMP __DATE__ " " __TIME__ /* __TIMESTAMP__ */ #define BROKER_VERSION "1.2.0.12" /* __VERSION__ */ #define PRODUCT_NAME "MQTT Daemon for Devices" static char* broker_version_eye = NULL; static char* broker_timestamp_eye = NULL; FUNC_ENTRY_NOLOG; broker_timestamp_eye = "AMQTDD_Timestamp " BUILD_TIMESTAMP; broker_version_eye = "AMQTDD_Version " BROKER_VERSION; BrokerState.version = BROKER_VERSION; BrokerState.timestamp = BUILD_TIMESTAMP; srand(time(NULL)); Heap_initialize(); Log_initialize(); Log(LOG_INFO, 9999, PRODUCT_NAME); Log(LOG_INFO, 9998, "Part of Project Mosquitto in Eclipse\n(" "http://projects.eclipse.org/projects/technology.mosquitto)"); getopts(argc, argv); if (Messages_initialize(&BrokerState) != 0) goto no_messages; Log(LOG_INFO, 53, NULL, BrokerState.version, BrokerState.timestamp); Log(LOG_INFO, 54, "%s %s", Messages_get(54, LOG_INFO), "" #if !defined(NO_BRIDGE) " bridge" #endif #if defined(MQTTMP) " MQTTMP" #endif #if defined(MQTTS) " MQTTS" #endif ); if ((rc = Broker_startup()) == 0) { SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/version", 0, BrokerState.version, strlen(BrokerState.version)); SubscriptionEngines_setRetained(BrokerState.se, "$SYS/broker/timestamp", 0, BrokerState.timestamp, strlen(BrokerState.timestamp)); while (BrokerState.state == BROKER_RUNNING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } Log(LOG_INFO, 46, NULL); #if !defined(NO_BRIDGE) Bridge_stop(&BrokerState.bridge); #endif while (BrokerState.state == BROKER_STOPPING) { Protocol_timeslice(); #if !defined(NO_BRIDGE) Bridge_timeslice(&BrokerState.bridge); #endif } } Broker_shutdown(rc); Log(LOG_INFO, 47, NULL); no_messages: Messages_terminate(); Log_terminate(); Heap_terminate(); /*FUNC_EXIT_NOLOG(rc); would anyone ever see this? */ return rc; }
/** * Log a message. If possible, all messages should be indexed by message number, and * the use of the format string should be minimized or negated altogether. If format is * provided, the message number is only used as a message label. * @param log_level the log level of the message * @param msgno the id of the message to use if the format string is NULL * @param aFormat the printf format string to be used if the message id does not exist * @param ... the printf inserts */ void Log(int log_level, int msgno, char* format, ...) { int islogmsg = 1; char* temp = NULL; static char msg_buf[256]; if (log_level < LOG_CONFIG) islogmsg = 0; #if defined(HIGH_PERFORMANCE) if (!islogmsg) #else if (!islogmsg && log_level < trace_settings.trace_level) #endif return; if (islogmsg && log_level < trace_settings.log_level) return; if (format == NULL && (temp = Messages_get(msgno, log_level)) != NULL) format = temp; if (!islogmsg) { static char trace_msg_buf[256]; va_list args; va_start(args, format); vsnprintf(trace_msg_buf, sizeof(trace_msg_buf), format, args); Log_trace(log_level, trace_msg_buf); va_end(args); return; } if (Log_recurse_flag == 0) { struct tm *timeinfo; char level_char = ' '; int buf_pos = 31; va_list args; #if defined(GETTIMEOFDAY) gettimeofday(&ts, NULL); timeinfo = localtime(&ts.tv_sec); #else ftime(&ts); timeinfo = localtime(&ts.time); #endif strftime(&msg_buf[7], 80, "%Y%m%d %H%M%S ", timeinfo); #if defined(GETTIMEOFDAY) sprintf(&msg_buf[22], ".%.3lu ", ts.tv_usec / 1000L); #else sprintf(&msg_buf[22], ".%.3hu ", ts.millitm); #endif buf_pos = 27; #if defined(GETTIMEOFDAY) if (ts.tv_sec == last_ts.tv_sec && ts.tv_usec == last_ts.tv_usec) #else if (ts.time == last_ts.time && ts.millitm == last_ts.millitm) #endif ++sametime_count; /* this message has the same timestamp as the last, so increase the sequence no */ else { sametime_count = 0; last_ts = ts; } sprintf(msg_buf, "(%.4d)", sametime_count); msg_buf[6] = ' '; level_char = " CDIAWESF"[log_level]; sprintf(&msg_buf[buf_pos], "%s%.4d%c ", MSG_PREFIX, msgno, level_char); buf_pos += 11; va_start(args, format); vsnprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, format, args); va_end(args); if (log_level >= LOG_ERROR) { char* filename = NULL; Log_recurse_flag = 1; filename = Broker_recordFFDC(&msg_buf[7]); Log_recurse_flag = 0; snprintf(&msg_buf[buf_pos], sizeof(msg_buf)-buf_pos, Messages_get(13, LOG_WARN), filename); } addToBuffer(log_buffer, msg_buf); #if !defined(WIN32) if (trace_settings.isdaemon) { static char priorities[] = { 7, 7, 7, 7, 6, 6, 5, 5, 4, 3, 1, 0}; syslog(priorities[log_level], "%s", &msg_buf[22]); } else { #endif printf("%s\n", &msg_buf[7]); fflush(stdout); #if !defined(WIN32) } #endif if (Log_publishFlag) { #define MAX_LOG_TOPIC_NAME_LEN 25 static char topic_buf[MAX_LOG_TOPIC_NAME_LEN]; sprintf(topic_buf, "$SYS/broker/log/%c/%.4d", level_char, msgno); Log_recurse_flag = 1; Log_Publish(topic_buf, &msg_buf[7]); Log_recurse_flag = 0; } } if (log_level == LOG_FATAL) exit(-1); }