static rc_t CC sts_print(KFmtHandler* formatter, const KStsFmtFlags flags, KWrtHandler* writer, const char* msg, va_list args) { rc_t rc = 0; char* nbuffer; size_t num_writ, remaining; uint32_t envc = 0; wrt_nvp_t envs[5]; char ebuffer[2048]; char mbuffer[2048]; KFmtWriter fmtwrt; assert(formatter != NULL); assert(writer != NULL); fmtwrt = formatter->formatter; if( fmtwrt == NULL ) { fmtwrt = KStsDefaultFormatter; } if( fmtwrt == KStsDefaultFormatter && writer->writer == NULL ) { /* default formatting with NULL writer -> silence */ return rc; } nbuffer = (char*)ebuffer; remaining = sizeof(ebuffer); do { #define FIX_UP() if(rc){break;} remaining -= num_writ; nbuffer += num_writ if( flags & (kstsFmtTimestamp | kstsFmtLocalTimestamp) ) { if( flags & kstsFmtLocalTimestamp ) { rc = LogSimpleTimestamp(nbuffer, remaining, &num_writ); } else { rc = LogTimestamp(nbuffer, remaining, &num_writ); } nbuffer[num_writ++] = '\0'; envs[envc].name = "timestamp"; envs[envc++].value = nbuffer; FIX_UP(); } if( flags & kstsFmtPid ) { rc = LogPID(nbuffer, remaining, &num_writ); nbuffer[num_writ++] = '\0'; envs[envc].name = "pid"; envs[envc++].value = nbuffer; FIX_UP(); } if( flags & kstsFmtAppName ) { rc = LogAppName(nbuffer, remaining, &num_writ); nbuffer[num_writ++] = '\0'; envs[envc].name = "app"; envs[envc++].value = nbuffer; FIX_UP(); } if( flags & kstsFmtAppVersion ) { rc = LogAppVersion(nbuffer, remaining, &num_writ); nbuffer[num_writ++] = '\0'; envs[envc].name = "version"; envs[envc++].value = nbuffer; FIX_UP(); } #undef FIX_UP } while(false); /* env must have one spare element for message added text below */ if( rc == 0 && envc >= (sizeof(envs)/sizeof(envs[0])) ) { rc = RC(rcRuntime, rcLog, rcLogging, rcTable, rcInsufficient); } nbuffer = (char*)mbuffer; remaining = sizeof(mbuffer); if( rc == 0 ) { if( flags & kstsFmtMessage ) { if( msg == NULL || msg[0] == '\0' ) { msg = "empty status message"; } do { va_list args_copy; va_copy(args_copy, args); rc = string_vprintf(nbuffer, remaining, &num_writ, msg, args_copy); va_end(args_copy); if( num_writ > remaining ) { if(nbuffer != mbuffer) { free(nbuffer); } nbuffer = malloc(remaining = num_writ); if( nbuffer == NULL ) { rc = RC(rcRuntime, rcLog, rcLogging, rcMemory, rcExhausted); } } else { if( rc == 0 ) { envs[envc].name = "message"; envs[envc++].value = nbuffer; } break; } } while( rc == 0 ); } } if( rc != 0 ) { /* print reason for failure */ rc = string_printf((char*)mbuffer, sizeof(mbuffer), NULL, "status failure: %R in '%s'", rc, msg); envs[envc].name = "message"; envs[envc++].value = mbuffer; } wrt_nvp_sort(envc, envs); rc = fmtwrt(formatter->data, writer, 0, NULL, envc, envs); if(nbuffer != mbuffer) { free(nbuffer); } return rc; }
static rc_t CC LoaderXMLFormatter( void* data, KWrtHandler* writer, size_t argc, const wrt_nvp_t args[], size_t envc, const wrt_nvp_t envs[]) { rc_t rc = 0; size_t i, remaining, num_writ = 0; XMLFormatterData* self = (XMLFormatterData*)data; char buffer[4096]; const char* severity, *msg_val = NULL; bool severity_std = false; char* pbuffer; const char* const tag_nvp_name = "severity"; const wrt_nvp_t* msg_nvp = NULL; static const char* tags[] = { "fatal", "system", "internal", "error", "warning", "info" }; msg_nvp = wrt_nvp_find(envc, envs, "message"); if( msg_nvp != NULL ) { msg_val = msg_nvp->value; } severity = wrt_nvp_find_value(argc, args, tag_nvp_name); if( severity == NULL ) { severity = wrt_nvp_find_value(envc, envs, tag_nvp_name); if( severity != NULL ) { severity_std = true; /* translate std severity name to full name */ for(i = 0; i < sizeof(tags)/sizeof(tags[0]); i++) { if( strncmp(severity, tags[i], strlen(severity)) == 0 ) { severity = tags[i]; break; } } } } if( severity == NULL ) { severity = "status"; } #define FIX_UP() if(rc != 0){break;} remaining -= num_writ; pbuffer += num_writ pbuffer = buffer; remaining = sizeof(buffer); do { size_t k, pq = envc; const wrt_nvp_t* p = envs; const char* subst = NULL; rc = LogInsertSpace("<", pbuffer, remaining, &num_writ); FIX_UP(); rc = LogInsertSpace(severity, pbuffer, remaining, &num_writ); FIX_UP(); /* print env first and than args! */ for(k = 0; rc == 0 && k < 2; k++) { for(i = 0; i < pq; i++ ) { if( strcmp(p[i].name, tag_nvp_name) == 0 ) { continue; } if( p == args ) { if( i == 0 && msg_nvp != NULL ) { /* grab args attr buffer start */ subst = pbuffer; } if( severity_std ) { /* allow only specific attributes from message into xml log for LOG calls with standard severity */ int x, yes = 0; static const char* allowed_attr[] = { "file", "line", "offset", "spot", "spot_name", "spotname" }; for(x = 0; x < sizeof(allowed_attr)/sizeof(allowed_attr[0]); x++) { if( strcasecmp(p[i].name, allowed_attr[x]) == 0 ) { yes = 1; break; } } if( !yes ) { continue; } } } rc = LogInsertSpace(" ", pbuffer, remaining, &num_writ); FIX_UP(); rc = XMLLogger_Encode(p[i].name, pbuffer, remaining, &num_writ); FIX_UP(); rc = LogInsertSpace("=\"", pbuffer, remaining, &num_writ); FIX_UP(); rc = XMLLogger_Encode(p[i].value, pbuffer, remaining, &num_writ); FIX_UP(); rc = LogInsertSpace("\"", pbuffer, remaining, &num_writ); FIX_UP(); } p = args; pq = argc; } if( subst != NULL && subst[0] != '\0' ) { /* hack 'message' to print curr argv to std log as text attr="value" */ ((wrt_nvp_t*)msg_nvp)->value = subst + 1; /* \0 terminated pre LogInsertSpace behavior */ if( (rc = self->fmt.formatter(self->fmt.data, &self->wrt, 0, NULL, envc, envs)) != 0 ) { break; } ((wrt_nvp_t*)msg_nvp)->value = msg_val; } rc = LogInsertSpace("/>\n", pbuffer, remaining, &num_writ); FIX_UP(); } while(false); if( self->file->file != NULL ) { if( rc != 0 ) { pbuffer = buffer; remaining = sizeof(buffer); rc = string_printf(pbuffer, remaining, & num_writ, "<error severity=\"err\" message=\"XML log failed: %R\"/>\n", rc); pbuffer += num_writ <= remaining ? num_writ : 0; } rc = KFileWrite(self->file->file, self->file->pos, buffer, pbuffer - buffer, &num_writ); self->file->pos += num_writ; } rc = self->fmt.formatter(self->fmt.data, &self->wrt, argc, args, envc, envs); return rc; }