Hi All,

 for some time I had been struggling with the logging system in my
scripts. I wanted it to automatically detect the status of last
executed command, print the customizable time stamp, work from within
functions, and so on. For me it took a couple of lines of echo, output
redirection, and if instructions to get what I wanted and needed.
 Then I created a log builtin, which I have cleaned now a much as I
could so the main idea is clear, and enclose as a diff against
bash-4.4-testing branched at 54a5fbe126d2a28913a81f7191d7ac6db70e1f43
.
 It is aimed at providing an uniform logging for bash. At the moment
it works as follows:

$ log "processing started."
[31867] Mon, 14 Dec 2015 12:32:41 +0100 processing started.

$ export LOG_FMT_HEADER="[ @%s %d-%m-%Y ]"
$ log "processing 10%."
[31867] [ @1450092818 14-12-2015 ] processing 10%.

$ function stat_file() { local stat; stat=`stat "${1}" 2>&1`; log
"getting status ($stat) ."; }
$ stat_file /tmp/it_is_here
[31867]stat_file [ @1450093235 14-12-2015 ] getting status (  File:
`/tmp/it_is_here'
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Access: 2015-12-14 12:40:01.000000000 +0100
Modify: 2015-12-14 12:40:01.000000000 +0100
Change: 2015-12-14 12:40:01.000000000 +0100) .
$ stat_file /tmp/it_is_not_here
[31867]stat_file [ @1450093237 14-12-2015 ] error. getting status
(stat: cannot stat `/tmp/it_is_not_here': No such file or directory) .

$ unset LOG_FMT_HEADER
$ mkdir /tmp/it_is_not_here/directory 2>/dev/null; log "creating
directory." >/dev/null;
[31867] Mon, 14 Dec 2015 12:52:43 +0100 error. creating directory.

$ log "done." 2>/dev/null
[31867] Mon, 14 Dec 2015 12:53:46 +0100 done.

 I provide the diff so you can try it; it still needs lot of work and attention.
 What do you think?

cheers,
pg
commit 9ff927b1e30371cc462b40bf32cd99510679f7bd
Author: Peter Grzybowski <mer...@narsil.org.pl>
Date:   Sun Dec 13 14:12:52 2015 +0100

    log bulitin: uniform bash logging.

diff --git a/Makefile.in b/Makefile.in
index 5260a06..98d0ff5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -491,7 +491,7 @@ BUILTIN_DEFS = $(DEFSRC)/alias.def $(DEFSRC)/bind.def 
$(DEFSRC)/break.def \
               $(DEFSRC)/exec.def $(DEFSRC)/exit.def $(DEFSRC)/fc.def \
               $(DEFSRC)/fg_bg.def $(DEFSRC)/hash.def $(DEFSRC)/help.def \
               $(DEFSRC)/history.def $(DEFSRC)/jobs.def $(DEFSRC)/kill.def \
-              $(DEFSRC)/let.def $(DEFSRC)/read.def $(DEFSRC)/return.def \
+              $(DEFSRC)/let.def $(DEFSRC)/log.def $(DEFSRC)/read.def 
$(DEFSRC)/return.def \
               $(DEFSRC)/set.def $(DEFSRC)/setattr.def $(DEFSRC)/shift.def \
               $(DEFSRC)/source.def $(DEFSRC)/suspend.def $(DEFSRC)/test.def \
               $(DEFSRC)/times.def $(DEFSRC)/trap.def $(DEFSRC)/type.def \
@@ -511,7 +511,7 @@ BUILTIN_OBJS = $(DEFDIR)/alias.o $(DEFDIR)/bind.o 
$(DEFDIR)/break.o \
               $(DEFDIR)/exec.o $(DEFDIR)/exit.o $(DEFDIR)/fc.o \
               $(DEFDIR)/fg_bg.o $(DEFDIR)/hash.o $(DEFDIR)/help.o \
               $(DEFDIR)/history.o $(DEFDIR)/jobs.o $(DEFDIR)/kill.o \
-              $(DEFDIR)/let.o $(DEFDIR)/pushd.o $(DEFDIR)/read.o \
+              $(DEFDIR)/let.o $(DEFDIR)/log.o $(DEFDIR)/pushd.o 
$(DEFDIR)/read.o \
               $(DEFDIR)/return.o $(DEFDIR)/shopt.o $(DEFDIR)/printf.o \
               $(DEFDIR)/set.o $(DEFDIR)/setattr.o $(DEFDIR)/shift.o \
               $(DEFDIR)/source.o $(DEFDIR)/suspend.o $(DEFDIR)/test.o \
@@ -1435,6 +1435,10 @@ builtins/let.o: command.h config.h 
${BASHINCDIR}/memalloc.h error.h general.h xm
 builtins/let.o: quit.h dispose_cmd.h make_cmd.h subst.h externs.h 
${BASHINCDIR}/stdc.h
 builtins/let.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h 
unwind_prot.h variables.h arrayfunc.h conftypes.h 
 builtins/let.o: pathnames.h
+builtins/log.o: command.h config.h ${BASHINCDIR}/memalloc.h error.h general.h 
xmalloc.h ${BASHINCDIR}/maxpath.h
+builtins/log.o: shell.h syntax.h bashjmp.h ${BASHINCDIR}/posixjmp.h sig.h 
unwind_prot.h variables.h arrayfunc.h conftypes.h
+builtins/log.o: dispose_cmd.h make_cmd.h subst.h externs.h ${BASHINCDIR}/stdc.h
+builtins/log.o: $(DEFSRC)/common.h quit.h pathnames.h
 builtins/printf.o: config.h ${BASHINCDIR}/memalloc.h bashjmp.h command.h 
error.h
 builtins/printf.o: general.h xmalloc.h quit.h dispose_cmd.h make_cmd.h subst.h
 builtins/printf.o: externs.h sig.h pathnames.h shell.h syntax.h unwind_prot.h
@@ -1597,6 +1601,7 @@ builtins/inlib.o: $(DEFSRC)/inlib.def
 builtins/jobs.o: $(DEFSRC)/jobs.def
 builtins/kill.o: $(DEFSRC)/kill.def
 builtins/let.o: $(DEFSRC)/let.def
+builtins/log.o: $(DEFSRC)/log.def
 builtins/mapfile.o: $(DEFSRC)/mapfile.def
 builtins/pushd.o: $(DEFSRC)/pushd.def
 builtins/read.o: $(DEFSRC)/read.def
diff --git a/builtins/Makefile.in b/builtins/Makefile.in
index 19dd384..b6615e7 100644
--- a/builtins/Makefile.in
+++ b/builtins/Makefile.in
@@ -137,7 +137,7 @@ DEFSRC =  $(srcdir)/alias.def $(srcdir)/bind.def 
$(srcdir)/break.def \
          $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \
          $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \
          $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \
-         $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \
+         $(srcdir)/let.def $(srcdir)/log.def $(srcdir)/read.def 
$(srcdir)/return.def \
          $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \
          $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \
          $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \
@@ -145,14 +145,14 @@ DEFSRC =  $(srcdir)/alias.def $(srcdir)/bind.def 
$(srcdir)/break.def \
          $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \
          $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def
 
-STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \
+STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c 
log_builtin.c \
                getopt.h 
 
 OFILES = builtins.o \
        alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \
        common.o declare.o echo.o enable.o eval.o evalfile.o \
        evalstring.o exec.o exit.o fc.o fg_bg.o hash.o help.o history.o \
-       jobs.o kill.o let.o mapfile.o \
+       jobs.o kill.o let.o log.o log_builtin.o mapfile.o \
        pushd.o read.o return.o set.o setattr.o shift.o source.o \
        suspend.o test.o times.o trap.o type.o ulimit.o umask.o \
        wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o
@@ -298,6 +298,7 @@ history.o: history.def
 jobs.o: jobs.def
 kill.o: kill.def
 let.o: let.def
+log.o: log.def
 mapfile.o: mapfile.def
 printf.o: printf.def
 pushd.o: pushd.def
@@ -373,6 +374,7 @@ getopt.o: $(srcdir)/getopt.h
 mkbuiltins.o: ../config.h $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
 mkbuiltins.o: ${BASHINCDIR}/filecntl.h
 mkbuiltins.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
+log_builtin.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/stdc.h 
$(BASHINCDIR)/memalloc.h
 
 # def files
 alias.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
@@ -524,6 +526,12 @@ let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h 
$(topdir)/make_cmd.h $(topdir)/s
 let.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
 let.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h 
$(topdir)/variables.h $(topdir)/conftypes.h
 let.o: ../pathnames.h
+log.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h 
$(topdir)/error.h
+log.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h 
$(topdir)/dispose_cmd.h
+log.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h
+log.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h 
$(topdir)/variables.h $(topdir)/conftypes.h
+log.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ../pathnames.h
+log.o: $(topdir)/sig.h
 printf.o: ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/bashjmp.h
 printf.o: $(topdir)/command.h $(topdir)/error.h $(topdir)/general.h 
$(topdir)/xmalloc.h
 printf.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -675,6 +683,7 @@ inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} 
$(BASHINCDIR)/gettext.h
 jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
+log_builtin.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 mapfile.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 mkbuiltins.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
 printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
diff --git a/builtins/log.def b/builtins/log.def
new file mode 100644
index 0000000..eb09756
--- /dev/null
+++ b/builtins/log.def
@@ -0,0 +1,87 @@
+This file is log.def, from which is created cd.c.  It implements the
+builtin "log" for bash uniform logging.
+
+Copyright (C) 1987-2015 Free Software Foundation, Inc.
+
+This file is part of GNU Bash, the Bourne Again SHell.
+
+Bash is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Bash 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+
+$PRODUCES log.c
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include "posixdir.h"
+#include "posixstat.h"
+#if defined (HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include <errno.h>
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "../flags.h"
+#include "maxpath.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+int log_builtin_main (WORD_LIST *list);
+
+$BUILTIN log
+$FUNCTION log_builtin
+$SHORT_DOC log [ -f file | -fd n ] message
+Output message according to format given in LOG_FMT_STRING.
+
+Options:
+  -f   file output message to file
+  -fd n output to given descriptor
+
+The format of the log message is controlled by LOG_FMT_STRING, the valid
+format directives are those of strftime(3), and:
+
+%L log message
+%f function name (same as $FUNCNAME)
+
+Depending on the status of the last executed command (as seen by $?) the 
+log builtin outputs message to stdout or stderr including the "error" tag.
+
+$END
+
+/* This builtin provides uniform bash logging facility */
+int
+log_builtin (list)
+     WORD_LIST *list;
+{
+
+         return log_builtin_main(list);
+}
+
diff --git a/builtins/log_builtin.c b/builtins/log_builtin.c
new file mode 100644
index 0000000..dc06ccf
--- /dev/null
+++ b/builtins/log_builtin.c
@@ -0,0 +1,93 @@
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include "posixdir.h"
+#include "posixstat.h"
+#if defined (HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include <errno.h>
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "../flags.h"
+#include "maxpath.h"
+#include "common.h"
+#include "bashgetopt.h"
+#include <time.h>
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern pid_t dollar_dollar_pid;
+extern int last_command_exit_value;
+extern SHELL_VAR *this_shell_function;
+
+#define LOG_FMT_STRING_VARIABLE_NAME "LOG_FMT_HEADER"
+#define LOG_DEFAULT_FMT "%a, %d %b %Y %T %z"
+#define LOG_MAX_TIMESTAMP_LENGTH 255
+#define LOG_MAX_FMT_STRING_LENGTH 64
+
+/* This builtin provides uniform bash logging facility */
+int log_builtin_main(WORD_LIST *list)
+{
+ SHELL_VAR *v;
+ char *format=LOG_DEFAULT_FMT;
+ time_t t;
+ struct tm *local_time;
+ char timestampbuffer[LOG_MAX_TIMESTAMP_LENGTH]={0};
+ char *function_name=NULL;
+ int format_length=0;
+
+ t=time(NULL);
+ local_time=localtime(&t);
+ if (local_time==NULL) {
+  return (EXECUTION_FAILURE);
+ }
+
+ v = find_variable (LOG_FMT_STRING_VARIABLE_NAME);
+ if (v!=NULL) {
+  format=get_string_value(LOG_FMT_STRING_VARIABLE_NAME);
+  if (format==NULL) {
+  }
+  format_length=strlen(format);
+  if (format_length<2||format_length>LOG_MAX_FMT_STRING_LENGTH) {
+   format=LOG_DEFAULT_FMT;
+  }
+ }
+
+ if (this_shell_function!=NULL) {
+  function_name=this_shell_function->name;
+ }
+
+ if (strftime(timestampbuffer,LOG_MAX_TIMESTAMP_LENGTH,format,local_time)==0) {
+  return (EXECUTION_FAILURE);
+ }
+ if (list==NULL) {
+  printf("%s \n",timestampbuffer);
+  return (EXECUTION_SUCCESS);
+ }
+
+ if (last_command_exit_value!=0) {
+  fprintf(stderr,"[%d]%s %s error. 
%s\n",dollar_dollar_pid,(function_name!=NULL)?function_name:"",timestampbuffer,list->word->word);
+ } else {
+  printf("[%d]%s %s 
%s\n",dollar_dollar_pid,(function_name!=NULL)?function_name:"",timestampbuffer,list->word->word);
+ }
+ return (EXECUTION_SUCCESS);
+}
+

Reply via email to