Skip to content

Commit cc9cfec

Browse files
committed
added command line options to set fields. added way to set pid from parent or remote pipe side
1 parent 69b097d commit cc9cfec

1 file changed

Lines changed: 138 additions & 47 deletions

File tree

src/log.cxx

Lines changed: 138 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
#include <stdio.h>
1313
#include <unistd.h>
1414
#include <string.h>
15+
#include <sys/types.h>
16+
#include <dirent.h>
17+
#include <sys/stat.h>
1518

1619

1720
using namespace AliceO2::InfoLogger;
@@ -21,77 +24,165 @@ void print_usage(){
2124
printf("Usage: log [options] message(s)\n");
2225
printf("Options: \n");
2326
printf(" -s [severity] Possible values: Info (default), Error, Fatal, Warning, Debug.\n");
24-
printf(" -x If set, reads data coming on stdin line by line\n");
27+
printf(" -o[key]=[value] Set a message field. Valid keys: context (Facility, Role, System, Detector, Partition, Run) and message options (Severity, Level, ErrorCode, SourceFile, SourceLine).\n");
28+
printf(" -x If set, reads data coming on stdin line by line.\n");
2529
printf(" and transmit them as messages (1 line = 1 message).\n");
2630
printf(" -h This help.\n");
2731
}
2832

2933

3034

35+
// reads an input string option, and sets accordingly msgOptions or msgContext variable.
36+
// returns 0 on success, -1 on error
37+
int processOption(const char *option, InfoLogger::InfoLoggerMessageOption &msgOptions, InfoLoggerContext &msgContext) {
38+
std::string s(option);
39+
size_t separatorPosition=s.find('=');
40+
if (separatorPosition==std::string::npos) {return -1;}
41+
s[separatorPosition]=0;
42+
const char *key=s.c_str();
43+
const char *value=&(option[separatorPosition+1]); // use input string instead of s, so that it's persistent
44+
45+
InfoLoggerContext::FieldName contextField;
46+
if (InfoLoggerContext::getFieldNameFromString(key,contextField)==0) {
47+
return msgContext.setField(contextField,value);
48+
} else {
49+
return InfoLogger::setMessageOption(key,value,msgOptions);
50+
}
51+
52+
return 0;
53+
}
54+
55+
56+
// find process id on other side of input pipe, if any.
57+
// this may not work if process has already exited.
58+
// returns PID, or zero if not found.
59+
pid_t findPipeProcess() {
60+
pid_t thePid=0;
61+
62+
// is stdin a pipe?
63+
pid_t myPid=getpid();
64+
char stdinPath[PATH_MAX];
65+
snprintf(stdinPath,sizeof(stdinPath),"/proc/%d/fd/0",(int)myPid);
66+
struct stat stdinStat;
67+
if (lstat(stdinPath,&stdinStat)==0) {
68+
// should be a symlink
69+
if (S_ISLNK(stdinStat.st_mode)) {
70+
char ofd[PATH_MAX];
71+
// read link name
72+
int i=readlink(stdinPath, ofd, sizeof(ofd));
73+
if (i>0) {
74+
ofd[i]=0; // set NUL-terminated string
75+
// we could check if name looks like: pipe:[231550]
76+
// but let's not restrict, it can work also for sockets, /dev/pts, etc
77+
78+
// browse process list to find other side process
79+
// which has a file descriptor open which is also a symlink, matching pipe name we use as stdin
80+
DIR *dp;
81+
struct dirent *ep;
82+
chdir("/proc");
83+
dp = opendir ("./");
84+
if (dp != NULL) {
85+
while ((ep = readdir (dp))) {
86+
int p=0;
87+
p=atoi(ep->d_name);
88+
if (p==myPid) {continue;}
89+
if (p!=0) {
90+
DIR *pid_dp;
91+
struct dirent *pid_ep;
92+
struct stat b;
93+
char fp[1024];
94+
snprintf(fp,sizeof(fp),"/proc/%d/fd",p);
95+
pid_dp=opendir(fp);
96+
if (pid_dp!=NULL) {
97+
while ((pid_ep = readdir (pid_dp))) {
98+
char fp2[1024];
99+
snprintf(fp2,sizeof(fp2),"/proc/%d/fd/%s",p,pid_ep->d_name);
100+
if (lstat(fp2,&b)==0) {
101+
if (S_ISLNK(b.st_mode)) {
102+
char ofd2[1024];
103+
int i;
104+
i=readlink (fp2, ofd2, sizeof(ofd2));
105+
if (i>0) {
106+
ofd2[i]=0; // set NUL-terminated string
107+
if (!strcmp(ofd2,ofd)) {
108+
thePid=p;
109+
break;
110+
}
111+
}
112+
}
113+
}
114+
if (thePid) {
115+
break;
116+
}
117+
}
118+
closedir(pid_dp);
119+
}
120+
}
121+
if (thePid) {
122+
break;
123+
}
124+
}
125+
closedir (dp);
126+
}
127+
}
128+
}
129+
}
130+
return thePid;
131+
}
132+
133+
134+
135+
136+
31137
int main(int argc, char **argv){
32138

33139
int optFromStdin=0; // 1 if logging from stdin, 0 when taking input from command line
34140

35-
InfoLogger::Severity severity=InfoLogger::Severity::Info;
36-
141+
InfoLogger::InfoLoggerMessageOption msgOptions=InfoLogger::undefinedMessageOption;
142+
msgOptions.severity=InfoLogger::Severity::Info;
143+
InfoLoggerContext msgContext;
144+
145+
// by default, use log context of parent process
146+
msgContext.refresh(getppid());
147+
37148
char option;
38149

39-
/* read options */
40-
while((option = getopt(argc, argv, "s:xh")) != -1){
150+
// read options
151+
while((option = getopt(argc, argv, "s:xo:h")) != -1){
41152
switch(option){
42153

43154
case 's':
44-
severity=getSeverityFromString(optarg);
155+
{
156+
InfoLogger::Severity severity=InfoLogger::Severity::Undefined;
157+
severity=InfoLogger::getSeverityFromString(optarg);
45158
if (severity==InfoLogger::Severity::Undefined) {
46159
printf("Bad severity\n");
47-
print_usage();
48160
return -1;
49161
}
162+
msgOptions.severity=severity;
163+
}
50164
break;
51165

52166
case 'x':
53-
optFromStdin=1;
54-
break;
55-
56-
/*
57-
// old options
58-
case 'f':
59-
facility=optarg;
60-
break;
61-
62-
63-
case 'l':
64-
level=infoLogger_getLevelFromString(optarg);
65-
if (level==UNDEFINED_INT) {
66-
printf("Bad level\n");
67-
print_usage();
68-
return -1;
167+
{
168+
optFromStdin=1;
169+
// try to find process sending messages to stdin
170+
pid_t pid=findPipeProcess();
171+
if (pid!=0) {
172+
msgContext.refresh(pid);
173+
}
69174
}
70175
break;
71-
72-
case 'd':
73-
detector=optarg;
74-
break;
75-
76-
case 'p':
77-
partition=optarg;
78-
break;
79-
80-
81-
case 'c':
82-
errcode=0;
83-
errcode=atoi(optarg);
84-
if (errcode<=0) {
85-
printf("Bad error code\n");
86-
print_usage();
176+
177+
case 'o':
178+
if (processOption(optarg,msgOptions,msgContext)) {
179+
printf("Can not parse option %s\n",optarg);
87180
return -1;
88181
}
89182
break;
90183

91-
case 'o':
92-
extraconfig=optarg;
93-
break;
94-
184+
/*
185+
// old options
95186
case 'z':
96187
configFile=optarg;
97188
break;
@@ -109,15 +200,15 @@ int main(int argc, char **argv){
109200

110201
InfoLogger theLog;
111202

112-
/* additionnal args = messages to send */
203+
// additionnal args = messages to send
113204
int i;
114205
for (i=optind; i < argc; i++) {
115-
theLog.log(severity,"%s",argv[i]);
206+
theLog.log(msgOptions,msgContext,"%s",argv[i]);
116207
}
117208

118209
// todo: catch exceptions
119210

120-
/* also read from stdin if option set */
211+
// also read from stdin if option set */
121212
if (optFromStdin) {
122213
LineBuffer lb; // buffer for input lines
123214
std::string msg;
@@ -132,7 +223,7 @@ int main(int argc, char **argv){
132223
break;
133224
}
134225
//infoLogger_msg_xt(UNDEFINED_STRING,UNDEFINED_INT,UNDEFINED_INT,facility,severity,level,msg);
135-
theLog.log(severity,"%s",msg.c_str());
226+
theLog.log(msgOptions,msgContext,"%s",msg.c_str());
136227
}
137228
if (eof) break;
138229
}

0 commit comments

Comments
 (0)