mirror of https://github.com/BOINC/boinc.git
264 lines
7.2 KiB
C++
264 lines
7.2 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2008 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// boinc_log: show stream of event-log messages from a client
|
|
//
|
|
// usage: boinc_log [--host hostname] [--passwd passwd]
|
|
|
|
#ifdef _WIN32
|
|
#include "boinc_win.h"
|
|
#include "win_util.h"
|
|
#else
|
|
#include "config.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <vector>
|
|
#include <string>
|
|
using std::vector;
|
|
using std::string;
|
|
|
|
#include "gui_rpc_client.h"
|
|
#include "error_numbers.h"
|
|
#include "util.h"
|
|
#include "str_util.h"
|
|
#include "str_replace.h"
|
|
#include "url.h"
|
|
#include "version.h"
|
|
#include "common_defs.h"
|
|
|
|
|
|
#define ARGX2(s1,s2) (!strcmp(argv[i], s1)||!strcmp(argv[i], s2))
|
|
#define ARG(S) ARGX2("-"#S, "--"#S)
|
|
|
|
|
|
// Global variables
|
|
char g_log_filename[256];
|
|
int g_message_sequence;
|
|
|
|
void version(){
|
|
printf("boinclog, built from %s \n", PACKAGE_STRING );
|
|
exit(0);
|
|
}
|
|
|
|
void usage() {
|
|
fprintf(stderr, "\n\
|
|
usage: boinclog [--host hostname] [--passwd passwd] [commands]\n\n\
|
|
Commands:\n\
|
|
--version, -V show version of the logging tool\n\
|
|
--datadir <directory> where the data directory is located\n\
|
|
"
|
|
);
|
|
exit(1);
|
|
}
|
|
|
|
void show_error(int retval) {
|
|
fprintf(stderr, "Error %d: %s\n", retval, boincerror(retval));
|
|
}
|
|
|
|
const char* prio_name(int prio) {
|
|
switch (prio) {
|
|
case MSG_INFO: return "low";
|
|
case MSG_USER_ALERT: return "user notification";
|
|
case MSG_INTERNAL_ERROR: return "internal error";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
|
|
void update_display() {
|
|
system("cls");
|
|
printf("BOINC Log Conversion Client %s\n", PACKAGE_VERSION);
|
|
printf("Log file: %s\n", g_log_filename);
|
|
printf("%d message(s) processed.\n\n", g_message_sequence);
|
|
printf("Press CTRL-C to exit application.\n");
|
|
}
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
unsigned int i;
|
|
int retval, port=0;
|
|
RPC_CLIENT rpc;
|
|
MESSAGES msgs;
|
|
char buf[256];
|
|
char datadir[256];
|
|
char hostname_buf[256], passwd_buf[256];
|
|
char *hostname = 0, *passwd = passwd_buf, *p;
|
|
struct tm* ptm;
|
|
time_t timestamp;
|
|
FILE* f = NULL;
|
|
std::string msg_datetime;
|
|
std::string msg_project;
|
|
std::string msg_priority;
|
|
std::string msg_type;
|
|
std::string msg_body;
|
|
std::string msg_tmp;
|
|
|
|
strlcpy(buf, "", sizeof(buf));
|
|
strlcpy(datadir, "", sizeof(datadir));
|
|
strlcpy(hostname_buf, "", sizeof(hostname_buf));
|
|
strlcpy(passwd_buf, "", sizeof(passwd_buf));
|
|
strlcpy(g_log_filename, "", sizeof(g_log_filename));
|
|
g_message_sequence = 0;
|
|
|
|
#if defined(_WIN32) && defined(USE_WINSOCK)
|
|
WSADATA wsdata;
|
|
retval = WSAStartup( MAKEWORD( 1, 1 ), &wsdata);
|
|
if (retval) {
|
|
fprintf(stderr, "WinsockInitialize: %d\n", retval);
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
for (i=1; i<(unsigned int)argc; i++) {
|
|
if (0) {
|
|
} else if (ARG(h)) {
|
|
usage();
|
|
} else if (ARG(help)) {
|
|
usage();
|
|
} else if (ARG(V)) {
|
|
version();
|
|
} else if (ARG(version)) {
|
|
version();
|
|
} else if (ARG(host)) {
|
|
if ((i+1) == (unsigned int)argc) usage();
|
|
hostname = hostname_buf;
|
|
safe_strcpy(hostname_buf, argv[++i]);
|
|
p = strchr(hostname, ':');
|
|
if (p) {
|
|
port = atoi(p+1);
|
|
*p=0;
|
|
}
|
|
} else if (ARG(passwd)) {
|
|
if ((i+1) == (unsigned int)argc) usage();
|
|
safe_strcpy(passwd_buf, argv[++i]);
|
|
} else if (ARG(datadir)) {
|
|
if ((i+1) == (unsigned int)argc) usage();
|
|
safe_strcpy(datadir, argv[++i]);
|
|
} else {
|
|
printf("Unknown option: %s\n", argv[i]);
|
|
usage();
|
|
}
|
|
}
|
|
|
|
if (strlen(datadir)) {
|
|
chdir(datadir);
|
|
} else {
|
|
#ifdef _WIN32
|
|
chdir_to_data_dir();
|
|
#endif
|
|
}
|
|
|
|
std::string msg;
|
|
read_gui_rpc_password(passwd_buf, msg);
|
|
|
|
retval = rpc.init(hostname, port);
|
|
if (retval) {
|
|
fprintf(stderr, "can't connect to %s\n", hostname?hostname:"local host");
|
|
show_error(retval);
|
|
exit(1);
|
|
}
|
|
|
|
if (passwd) {
|
|
retval = rpc.authorize(passwd);
|
|
if (retval) {
|
|
fprintf(stderr, "authorization failure: %d\n", retval);
|
|
show_error(retval);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
// Construct a unique filename for the output.
|
|
time(×tamp);
|
|
ptm = localtime(×tamp);
|
|
strftime(g_log_filename, sizeof(g_log_filename), "%Y%m%d%H%M.log", ptm);
|
|
|
|
// Open the new log file for output
|
|
f = fopen(g_log_filename, "w");
|
|
setbuf(f, NULL);
|
|
|
|
while(true) {
|
|
update_display();
|
|
|
|
msgs.clear();
|
|
|
|
rpc.get_messages(g_message_sequence, msgs);
|
|
|
|
for (i=0; i<msgs.messages.size(); i++) {
|
|
MESSAGE* pMsg = msgs.messages[i];
|
|
|
|
msg_datetime.clear();
|
|
msg_project.clear();
|
|
msg_priority.clear();
|
|
msg_type.clear();
|
|
msg_body.clear();
|
|
|
|
msg_datetime = time_to_string(double(pMsg->timestamp));
|
|
msg_project = pMsg->project;
|
|
msg_priority = prio_name(pMsg->priority);
|
|
msg_body = pMsg->body;
|
|
if (pMsg->body[0] == '[') {
|
|
msg_type = pMsg->body.substr(1, pMsg->body.find(']') - 1);
|
|
}
|
|
|
|
// If a message type is found in the message body, remove it from
|
|
// the message body
|
|
if (!msg_type.empty()) {
|
|
msg_tmp = std::string("[") + msg_type + std::string("] ");
|
|
msg_body.replace(0, msg_tmp.size(), "");
|
|
}
|
|
|
|
// If the last character if the message body is a newline character,
|
|
// remove it before continueing on. Standard BOINC messages contain
|
|
// a newline character at the end.
|
|
if (msg_body[msg_body.size() - 1] == '\n') {
|
|
msg_body[msg_body.size() - 1] = ' ';
|
|
}
|
|
|
|
// If line feeds are detected in the message body, replace them with
|
|
// the pipe symbol.
|
|
for (unsigned int j = 0; j < msg_body.size(); j++) {
|
|
if (msg_body[j] == '\n') {
|
|
msg_body[j] = '^';
|
|
}
|
|
}
|
|
|
|
// Dump to tab delimited file
|
|
fprintf(f,
|
|
"%s\t%s\t%s\t%s\t%s\n",
|
|
msg_datetime.c_str(),
|
|
msg_priority.c_str(),
|
|
msg_project.c_str(),
|
|
msg_type.c_str(),
|
|
msg_body.c_str()
|
|
);
|
|
|
|
g_message_sequence = pMsg->seqno;
|
|
}
|
|
|
|
boinc_sleep(1.0);
|
|
}
|
|
|
|
#if defined(_WIN32) && defined(USE_WINSOCK)
|
|
WSACleanup();
|
|
#endif
|
|
exit(retval);
|
|
}
|