tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Feed facility/priority to logger(1) via stdin - desirable extension or bad idea?



[re-sent due to wrong patch included + wrong address of netbsd-userlevel, please apologize duplicates]

Hello,

On 07.10.22 21:39, Mouse wrote:
Is there some reason you don't actually syslog() the log messages,
then, rather than sending them down a pipe?  It sounds to me as though
you are going to have to make your log generator logging-aware, but,
then, I don't see what benefit you get from piping the output to a tool
instead of just logging it directly.  (The obvious (to me) benefit is
that you can control facility and priority with the logging tool
instead of wiring it into the code, but here you're pushing it back
into the log-generation code anyway.)

Besides the things I already wrote in my last reply, this passage got me thinking again. You raised an important point - the approach of accepting the syslog log via stdin implies the requirement for the logging program to "speak" the syslog log. But this is exactly what I want to avoid with the whole thing ;-) I would rather set a fixed facility by logger parameter and only read the log level from stdin. This should then also be coded in a form that it can be reproduced very easily and intuitively e.g. by a script.

I've implemented a working draft prototype of what I'd consider useful, and I'm attaching the patch in case anyone is interested.

From the user's point of view, the change consists of an additional command line parameter (-F).

With this parameter, one can set the facility for the logger (unlike -p, which sets facility + log level). The parameter also activates special handling of all lines read via stdin. In this particular mode, the first characters read per line are expected to contain the log level in plain text (info, alert, err, emerg...), terminated by the pipe character. The pipe character separates the log level from the actual text to be logged.

This then makes the following possible, for example:

```
❯ echo "info|This in an informational message"|logger -F local2
❯ echo "alert|This in an alert message"|logger -F local2
```

and

```
#minute hour    mday    month   wday    command
#
0 */6 * * * /home/mpeterma/zdump backup 2>&1 | logger -F local2
```

I understand that my use case may be a more specialized one. Using the example above (crontab), the advantage of the solution is that the called program doesn't need deep knowledge of the logging protocol used. The only point of contact is the naming of the loglevels, which is oriented on the syslog standard. Otherwise, the only communication is via stderr - a way that is available in every conceivable programming language. The program itself can recognize at runtime whether it writes to a terminal or to stderr (pipe). Depending on this, the program can adjust the contents of the output. In the case of terminal, for example, I let it prepend a timestamp and color-code the loglevel. In case of stderr I let prepend the loglevel + "|" symbol, which allows the modified logger with matching loglevel to log with the set facility. Another advantage is that the logger process is started only once when the program is started, instead of every time a log line is written.

For my use case this approach is the most practical way at the moment. In contrast, I can't think of a practical use case for the comment included in the original logger code (parsing the syslog log via stdin). Did I miss something in the process?

I am very grateful for any suggestions, criticism and food for thought.

Kind regards
Matthias

--- /build/netbsd-current/src/usr.bin/logger/logger.c	2012-04-27 08:30:48.000000000 +0200
+++ journal/netbsd/logger/logger.c	2022-10-16 10:16:02.649411028 +0200
@@ -66,7 +66,7 @@
 int
 main(int argc, char *argv[])
 {
-	int ch, logflags, pri;
+	int ch, logflags, fac, pri, prioflag;
 	const char *tag;
 	const char *sd = "-";
 	const char *msgid = "-";
@@ -75,7 +75,8 @@
 	tag = NULL;
 	pri = LOG_NOTICE;
 	logflags = 0;
-	while ((ch = getopt(argc, argv, "cd:f:im:np:st:")) != -1)
+	prioflag = 0;
+	while ((ch = getopt(argc, argv, "cd:f:F:im:np:st:")) != -1)
 		switch((char)ch) {
 		case 'c':	/* log to console */
 			logflags |= LOG_CONS;
@@ -99,6 +100,12 @@
 		case 'p':		/* priority */
 			pri = pencode(optarg);
 			break;
+		case 'F':		/* set fixed facility */
+			fac = decode(optarg, facilitynames);
+			if (fac < 0)
+				errx(EXIT_FAILURE, "unknown facility name: %s", optarg);
+			prioflag = 1;
+			break;
 		case 's':		/* log to standard error */
 			logflags |= LOG_PERROR;
 			break;
@@ -138,13 +145,39 @@
 		}
 		if (p != buf)
 			syslogp(pri, msgid, sd, "%s", buf);
-	} else	/* TODO: allow syslog-protocol messages from file/stdin
-		 *       but that will require parsing the line to split
-		 *       it into three fields.
-		 */
-		while (fgets(buf, sizeof(buf), stdin) != NULL)
-			syslogp(pri, msgid, sd, "%s", buf);
-
+	} else {	
+		while (fgets(buf, sizeof(buf), stdin) != NULL) {
+			if (prioflag == 1) {
+				char *ptr;
+				int lev;
+				
+				for (ptr = buf; *ptr != '\0' && *ptr != '|'; ptr++);
+				if (*ptr != '\0') {
+					/* found encoded log level, decode */
+					*ptr = '\0';
+					lev = decode(buf, prioritynames);
+					if (lev == -1) { 
+						/* in case the encoded log level is unknown,
+						 * we first log this fact, then set the log 
+						 * level to a default 
+						 */
+						pri = ((LOG_EMERG & LOG_PRIMASK) | (fac & LOG_FACMASK));
+						syslogp(pri, msgid, sd, "unknown log level: %s", buf);
+						lev = LOG_NOTICE;
+					}
+					ptr++;
+				} else {
+					/* found no encoded log level, use default */
+					ptr = buf;
+					lev = LOG_NOTICE;
+				}
+				pri = ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+				syslogp(pri, msgid, sd, "%s", ptr);
+			} else {   
+				syslogp(pri, msgid, sd, "%s", buf);
+			}
+		}
+	}
 	exit(EXIT_SUCCESS);
 	/* NOTREACHED */
 }
@@ -197,7 +230,7 @@
 
 	(void)fprintf(stderr,
 	    "Usage: %s [-cins] [-d SD] [-f file] [-m msgid] "
-	    "[-p pri] [-t tag] [message ...]\n",
+	    "[-p pri] [-F facility] [-t tag] [message ...]\n",
 	    getprogname());
 	exit(EXIT_FAILURE);
 }

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature



Home | Main Index | Thread Index | Old Index