From c8d1b88849c9aadd4f31e25c7ed82533c75d2738 Mon Sep 17 00:00:00 2001 From: arjen Date: Thu, 4 Dec 2003 10:38:09 +0000 Subject: [PATCH] Major redesign. All input is handled through XML. Raw input data is first transformed into an XML document for further processing. A collection of polymorphic classes handle the transformation of various input formats into XML. Classifying input data is done with a finite improbability calculation. --- src/gcm_input/Makefile.am | 4 +- src/gcm_input/Makefile.in | 432 ++++++++++--------- src/gcm_input/access_cooker.cpp | 15 +- src/gcm_input/gcm_input.cpp | 56 ++- src/gcm_input/log_filter.cpp | 78 ++++ src/gcm_input/log_filter.h | 76 ++++ src/gcm_input/message.cpp | 905 ++++++++++++++++----------------------- src/gcm_input/message.h | 98 ++--- src/gcm_input/message_buffer.h | 111 +++++ src/gcm_input/message_filter.cpp | 174 ++++++++ src/gcm_input/message_filter.h | 98 +++++ src/gcm_input/rpm_filter.cpp | 134 ++++++ src/gcm_input/rpm_filter.h | 109 +++++ src/gcm_input/xml_cooker.cpp | 69 +++ src/gcm_input/xml_cooker.h | 79 ++++ 15 files changed, 1598 insertions(+), 840 deletions(-) create mode 100644 src/gcm_input/log_filter.cpp create mode 100644 src/gcm_input/log_filter.h create mode 100644 src/gcm_input/message_buffer.h create mode 100644 src/gcm_input/message_filter.cpp create mode 100644 src/gcm_input/message_filter.h create mode 100644 src/gcm_input/rpm_filter.cpp create mode 100644 src/gcm_input/rpm_filter.h create mode 100644 src/gcm_input/xml_cooker.cpp create mode 100644 src/gcm_input/xml_cooker.h diff --git a/src/gcm_input/Makefile.am b/src/gcm_input/Makefile.am index 646e560..a46f49b 100644 --- a/src/gcm_input/Makefile.am +++ b/src/gcm_input/Makefile.am @@ -5,6 +5,8 @@ INCLUDES = -I../include LDADD = ../lib/libgnucomo.a gcm_input_SOURCES = gcm_input.cpp message.cpp string_utils.cpp syslog_cooker.cpp \ - irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp + irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp \ + xml_cooker.cpp \ + message_filter.cpp log_filter.cpp rpm_filter.cpp logrunner_SOURCES = logrunner.cpp string_utils.cpp diff --git a/src/gcm_input/Makefile.in b/src/gcm_input/Makefile.in index c2c7d28..98c3f81 100644 --- a/src/gcm_input/Makefile.in +++ b/src/gcm_input/Makefile.in @@ -1,6 +1,8 @@ -# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am +# Makefile.in generated by automake 1.6.3 from Makefile.am. +# @configure_input@ -# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +# Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -10,7 +12,7 @@ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. - +@SET_MAKE@ SHELL = @SHELL@ srcdir = @srcdir@ @@ -31,13 +33,9 @@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include - -DESTDIR = - pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ - top_builddir = ../.. ACLOCAL = @ACLOCAL@ @@ -45,30 +43,50 @@ AUTOCONF = @AUTOCONF@ AUTOMAKE = @AUTOMAKE@ AUTOHEADER = @AUTOHEADER@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) transform = @program_transform_name@ - NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : + +EXEEXT = @EXEEXT@ +OBJEXT = @OBJEXT@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +AMTAR = @AMTAR@ AWK = @AWK@ CC = @CC@ CPP = @CPP@ CXX = @CXX@ +DEPDIR = @DEPDIR@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LN_S = @LN_S@ -MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ +STRIP = @STRIP@ VERSION = @VERSION@ XML_CONFIG = @XML_CONFIG@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ YACC = @YACC@ +am__include = @am__include@ +am__quote = @am__quote@ +install_sh = @install_sh@ bin_PROGRAMS = gcm_input logrunner @@ -76,283 +94,277 @@ INCLUDES = -I../include LDADD = ../lib/libgnucomo.a gcm_input_SOURCES = gcm_input.cpp message.cpp string_utils.cpp syslog_cooker.cpp \ - irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp + irix_syslog_cooker.cpp access_cooker.cpp error_cooker.cpp \ + xml_cooker.cpp \ + message_filter.cpp log_filter.cpp rpm_filter.cpp logrunner_SOURCES = logrunner.cpp string_utils.cpp +subdir = src/gcm_input mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_CLEAN_FILES = -PROGRAMS = $(bin_PROGRAMS) - +CONFIG_CLEAN_FILES = +bin_PROGRAMS = gcm_input$(EXEEXT) logrunner$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + +am_gcm_input_OBJECTS = gcm_input.$(OBJEXT) message.$(OBJEXT) \ + string_utils.$(OBJEXT) syslog_cooker.$(OBJEXT) \ + irix_syslog_cooker.$(OBJEXT) access_cooker.$(OBJEXT) \ + error_cooker.$(OBJEXT) xml_cooker.$(OBJEXT) \ + message_filter.$(OBJEXT) log_filter.$(OBJEXT) \ + rpm_filter.$(OBJEXT) +gcm_input_OBJECTS = $(am_gcm_input_OBJECTS) +gcm_input_LDADD = $(LDADD) +gcm_input_DEPENDENCIES = ../lib/libgnucomo.a +gcm_input_LDFLAGS = +am_logrunner_OBJECTS = logrunner.$(OBJEXT) string_utils.$(OBJEXT) +logrunner_OBJECTS = $(am_logrunner_OBJECTS) +logrunner_LDADD = $(LDADD) +logrunner_DEPENDENCIES = ../lib/libgnucomo.a +logrunner_LDFLAGS = -DEFS = @DEFS@ -I. -I$(srcdir) +DEFS = @DEFS@ +DEFAULT_INCLUDES = -I. -I$(srcdir) CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ -X_CFLAGS = @X_CFLAGS@ -X_LIBS = @X_LIBS@ -X_EXTRA_LIBS = @X_EXTRA_LIBS@ -X_PRE_LIBS = @X_PRE_LIBS@ -gcm_input_OBJECTS = gcm_input.o message.o string_utils.o \ -syslog_cooker.o irix_syslog_cooker.o access_cooker.o error_cooker.o -gcm_input_LDADD = $(LDADD) -gcm_input_DEPENDENCIES = ../lib/libgnucomo.a -gcm_input_LDFLAGS = -logrunner_OBJECTS = logrunner.o string_utils.o -logrunner_LDADD = $(LDADD) -logrunner_DEPENDENCIES = ../lib/libgnucomo.a -logrunner_LDFLAGS = -CXXFLAGS = @CXXFLAGS@ -CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/access_cooker.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/error_cooker.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/gcm_input.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/irix_syslog_cooker.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/log_filter.Po ./$(DEPDIR)/logrunner.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/message.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/message_filter.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/rpm_filter.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/string_utils.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/syslog_cooker.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/xml_cooker.Po +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) -CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ -DIST_COMMON = Makefile.am Makefile.in - - -DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) - -TAR = gtar -GZIP_ENV = --best -DEP_FILES = .deps/access_cooker.P .deps/error_cooker.P \ -.deps/gcm_input.P .deps/irix_syslog_cooker.P .deps/logrunner.P \ -.deps/message.P .deps/string_utils.P .deps/syslog_cooker.P +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +CXXFLAGS = @CXXFLAGS@ +DIST_SOURCES = $(gcm_input_SOURCES) $(logrunner_SOURCES) +DIST_COMMON = Makefile.am Makefile.in SOURCES = $(gcm_input_SOURCES) $(logrunner_SOURCES) -OBJECTS = $(gcm_input_OBJECTS) $(logrunner_OBJECTS) - -all: all-redirect -.SUFFIXES: -.SUFFIXES: .S .c .cpp .o .s -$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --gnu src/gcm_input/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - - -mostlyclean-binPROGRAMS: - -clean-binPROGRAMS: - -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) - -distclean-binPROGRAMS: - -maintainer-clean-binPROGRAMS: +all: all-am +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/gcm_input/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ - $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \ else :; fi; \ done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) - list='$(bin_PROGRAMS)'; for p in $$list; do \ - rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ done -.s.o: - $(COMPILE) -c $< - -.S.o: - $(COMPILE) -c $< +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +gcm_input$(EXEEXT): $(gcm_input_OBJECTS) $(gcm_input_DEPENDENCIES) + @rm -f gcm_input$(EXEEXT) + $(CXXLINK) $(gcm_input_LDFLAGS) $(gcm_input_OBJECTS) $(gcm_input_LDADD) $(LIBS) +logrunner$(EXEEXT): $(logrunner_OBJECTS) $(logrunner_DEPENDENCIES) + @rm -f logrunner$(EXEEXT) + $(CXXLINK) $(logrunner_LDFLAGS) $(logrunner_OBJECTS) $(logrunner_LDADD) $(LIBS) mostlyclean-compile: - -rm -f *.o core *.core - -clean-compile: + -rm -f *.$(OBJEXT) core *.core distclean-compile: -rm -f *.tab.c -maintainer-clean-compile: +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/access_cooker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error_cooker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcm_input.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irix_syslog_cooker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logrunner.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpm_filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/string_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syslog_cooker.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml_cooker.Po@am__quote@ -gcm_input: $(gcm_input_OBJECTS) $(gcm_input_DEPENDENCIES) - @rm -f gcm_input - $(CXXLINK) $(gcm_input_LDFLAGS) $(gcm_input_OBJECTS) $(gcm_input_LDADD) $(LIBS) +distclean-depend: + -rm -rf ./$(DEPDIR) -logrunner: $(logrunner_OBJECTS) $(logrunner_DEPENDENCIES) - @rm -f logrunner - $(CXXLINK) $(logrunner_LDFLAGS) $(logrunner_OBJECTS) $(logrunner_LDADD) $(LIBS) .cpp.o: - $(CXXCOMPILE) -c $< +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(CXXCOMPILE) -c -o $@ `cygpath -w $<` +CXXDEPMODE = @CXXDEPMODE@ +uninstall-info-am: + +ETAGS = etags +ETAGSFLAGS = tags: TAGS -ID: $(HEADERS) $(SOURCES) $(LISP) - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - here=`pwd` && cd $(srcdir) \ - && mkid -f$$here/ID $$unique $(LISP) + mkid -fID $$unique -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ - list='$(SOURCES) $(HEADERS)'; \ - unique=`for i in $$list; do echo $$i; done | \ - awk ' { files[$$0] = 1; } \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ - test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) - -mostlyclean-tags: + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique -clean-tags: +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here distclean-tags: - -rm -f TAGS ID - -maintainer-clean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) - -subdir = src/gcm_input +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) distdir: $(DISTFILES) - here=`cd $(top_builddir) && pwd`; \ - top_distdir=`cd $(top_distdir) && pwd`; \ - distdir=`cd $(distdir) && pwd`; \ - cd $(top_srcdir) \ - && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu src/gcm_input/Makefile - @for file in $(DISTFILES); do \ - d=$(srcdir); \ + @list='$(DISTFILES)'; for file in $$list; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ if test -d $$d/$$file; then \ - cp -pr $$d/$$file $(distdir)/$$file; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file || :; \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ fi; \ done - -DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) - --include $(DEP_FILES) - -mostlyclean-depend: - -clean-depend: - -distclean-depend: - -rm -rf .deps - -maintainer-clean-depend: - -%.o: %.c - @echo '$(COMPILE) -c $<'; \ - $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-cp .deps/$(*F).pp .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm .deps/$(*F).pp - -%.lo: %.c - @echo '$(LTCOMPILE) -c $<'; \ - $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*F).pp > .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm -f .deps/$(*F).pp - -%.o: %.cpp - @echo '$(CXXCOMPILE) -c $<'; \ - $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-cp .deps/$(*F).pp .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm .deps/$(*F).pp - -%.lo: %.cpp - @echo '$(LTCXXCOMPILE) -c $<'; \ - $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*F).pp > .deps/$(*F).P; \ - tr ' ' '\012' < .deps/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*F).P; \ - rm -f .deps/$(*F).pp -info-am: -info: info-am -dvi-am: -dvi: dvi-am check-am: all-am check: check-am -installcheck-am: -installcheck: installcheck-am -install-exec-am: install-binPROGRAMS -install-exec: install-exec-am +all-am: Makefile $(PROGRAMS) -install-data-am: -install-data: install-data-am +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am install: install-am -uninstall-am: uninstall-binPROGRAMS +install-exec: install-exec-am +install-data: install-data-am uninstall: uninstall-am -all-am: Makefile $(PROGRAMS) -all-redirect: all-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install -installdirs: - $(mkinstalldirs) $(DESTDIR)$(bindir) +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -rm -f Makefile $(CONFIG_CLEAN_FILES) - -rm -f config.cache config.log stamp-h stamp-h[0-9]* maintainer-clean-generic: -mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ - mostlyclean-tags mostlyclean-depend mostlyclean-generic + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am -mostlyclean: mostlyclean-am +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am -clean-am: clean-binPROGRAMS clean-compile clean-tags clean-depend \ - clean-generic mostlyclean-am +distclean: distclean-am -clean: clean-am +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-tags -distclean-am: distclean-binPROGRAMS distclean-compile distclean-tags \ - distclean-depend distclean-generic clean-am +dvi: dvi-am -distclean: distclean-am +dvi-am: -maintainer-clean-am: maintainer-clean-binPROGRAMS \ - maintainer-clean-compile maintainer-clean-tags \ - maintainer-clean-depend maintainer-clean-generic \ - distclean-am - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-binPROGRAMS + +install-info: install-info-am + +install-man: + +installcheck-am: maintainer-clean: maintainer-clean-am -.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ -maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ -mostlyclean-compile distclean-compile clean-compile \ -maintainer-clean-compile tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir mostlyclean-depend \ -distclean-depend clean-depend maintainer-clean-depend info-am info \ -dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ -install-exec install-data-am install-data install-am install \ -uninstall-am uninstall all-redirect all-am all installdirs \ -mostlyclean-generic distclean-generic clean-generic \ -maintainer-clean-generic clean mostlyclean distclean maintainer-clean +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +uninstall-am: uninstall-binPROGRAMS uninstall-info-am +.PHONY: GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic distclean distclean-compile distclean-depend \ + distclean-generic distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/gcm_input/access_cooker.cpp b/src/gcm_input/access_cooker.cpp index 339114b..5188204 100644 --- a/src/gcm_input/access_cooker.cpp +++ b/src/gcm_input/access_cooker.cpp @@ -8,7 +8,7 @@ *********************** ** FILE NAME : access_cooker.cpp ** SYSTEM NAME : -** VERSION NUMBER : $Revision: 1.1 $ +** VERSION NUMBER : $Revision: 1.2 $ ** ** DESCRIPTION : Cooks Apache http daemon access log lines ** @@ -26,7 +26,14 @@ /***************************** $Log: access_cooker.cpp,v $ - Revision 1.1 2003-08-11 16:56:15 arjen + Revision 1.2 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + + Revision 1.1 2003/08/11 16:56:15 arjen Different kinds of log files are parsed by a collection of objects of different classes, derived from the base class line_cooker Depending on the message content or the message_type element in @@ -38,13 +45,13 @@ *****************************/ -/* static const char *RCSID = "$Id: access_cooker.cpp,v 1.1 2003-08-11 16:56:15 arjen Exp $"; */ +/* static const char *RCSID = "$Id: access_cooker.cpp,v 1.2 2003-12-04 10:38:09 arjen Exp $"; */ #include #include "access_cooker.h" -static const regex re_accesslog("(GET|POST) .+ HTTP"); +static const regex re_accesslog("(GET|POST|HEAD) .+ HTTP"); bool access_cooker::check_pattern(String logline) { diff --git a/src/gcm_input/gcm_input.cpp b/src/gcm_input/gcm_input.cpp index 4215aa4..b85fe9a 100644 --- a/src/gcm_input/gcm_input.cpp +++ b/src/gcm_input/gcm_input.cpp @@ -7,7 +7,7 @@ *********************** ** FILE NAME : gcm_input.cpp ** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring -** VERSION NUMBER : $Revision: 1.11 $ +** VERSION NUMBER : $Revision: 1.12 $ ** ** DESCRIPTION : Application to store client messages into the database ** The client message contains a log file from one of the @@ -48,13 +48,20 @@ ******************************** ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl ** CREATION DATE : Aug 29, 2002 -** LAST UPDATE : Aug 11, 2003 +** LAST UPDATE : Nov 26, 2003 ** MODIFICATIONS : **************************************************************************/ /***************************** $Log: gcm_input.cpp,v $ - Revision 1.11 2003-10-27 13:00:15 arjen + Revision 1.12 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + + Revision 1.11 2003/10/27 13:00:15 arjen Catch exceptions from the database library Revision 1.10 2003/09/03 06:58:31 arjen @@ -103,13 +110,17 @@ *****************************/ -static const char *RCSID = "$Id: gcm_input.cpp,v 1.11 2003-10-27 13:00:15 arjen Exp $"; +static const char *RCSID = "$Id: gcm_input.cpp,v 1.12 2003-12-04 10:38:09 arjen Exp $"; #include #include #include "message.h" +#include "log_filter.h" +#include "rpm_filter.h" + +#include "xml_cooker.h" #include "syslog_cooker.h" #include "irix_syslog_cooker.h" #include "access_cooker.h" @@ -118,7 +129,7 @@ static const char *RCSID = "$Id: gcm_input.cpp,v 1.11 2003-10-27 13:00:15 arjen bool verbose = false; bool testmode = false; bool incremental = false; -std::ostream *log = &std::cerr; +std::ostream *Log = &std::cerr; static char *Version = "gcm_input version 0.0.8 - Sep 04, 2003"; @@ -236,17 +247,17 @@ int main(int argc, char *argv[]) } else { - log = &logfile; + Log = &logfile; } } verbose = verbose || level > 0; if (verbose) { - *log << "Hostname = " << hostname; - *log << " Arrival = " << arrival; - *log << " Service = " << service << "\n"; - *log << "Config OK.\n"; + *Log << "Hostname = " << hostname; + *Log << " Arrival = " << arrival; + *Log << " Service = " << service << "\n"; + *Log << "Config OK.\n"; } /* Try to connect to the database */ @@ -257,15 +268,24 @@ int main(int argc, char *argv[]) { client_message msg(&std::cin, db); + + message_filter shortcircuit(hostname, arrival, service); + log_filter lf(hostname, arrival, service); + rpm_filter rf(hostname, arrival, service); + syslog_cooker slc; irix_syslog_cooker islc; access_cooker alc; error_cooker elc; + xml_cooker xlc; + rpm_cooker rlc; - msg.add_cooker(&slc); - msg.add_cooker(&islc); - msg.add_cooker(&alc); - msg.add_cooker(&elc); + msg.add_cooker(&xlc, &shortcircuit); + msg.add_cooker(&slc, &lf); + msg.add_cooker(&islc, &lf); + msg.add_cooker(&alc, &lf); + msg.add_cooker(&elc, &lf); + msg.add_cooker(&rlc, &rf); if (msg.classify(hostname, arrival, service) > 0.9) { @@ -273,17 +293,17 @@ int main(int argc, char *argv[]) { msg.enter(); } - catch (exception &e) + catch (std::exception &e) { - *log << "Caught an exception: " << e.what() << "\n"; + *Log << "Caught an exception: " << e.what() << "\n"; } } return 0; } else { - *log << "gcm_input: Can not connect to database.\n"; - *log << "Gcm_input finished at " << Now() << ".\n"; + *Log << "gcm_input: Can not connect to database.\n"; + *Log << "Gcm_input finished at " << Now() << ".\n"; return 1; } } diff --git a/src/gcm_input/log_filter.cpp b/src/gcm_input/log_filter.cpp new file mode 100644 index 0000000..e7b78dd --- /dev/null +++ b/src/gcm_input/log_filter.cpp @@ -0,0 +1,78 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : log_filter.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Implementation of the log_filter class +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 26, 2003 +** LAST UPDATE : Nov 26, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: log_filter.cpp,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: log_filter.cpp,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include "log_filter.h" + +extern String XML_Entities(String s); + +/*========================================================================= +** NAME : constructXML +** SYNOPSIS : int constructXML(message_buffer &in, strstream &xml) +** PARAMETERS : +** RETURN VALUE : None +** +** DESCRIPTION : Create the body for a Gnucomo XML document. Each line +** of input from the log file is put in a XML element. +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 26, 2003 +**========================================================================= +*/ + +void log_filter::construct_XML(message_buffer &in, std::strstream &xml) +{ + String line; + + scan_email_header(in); + construct_header(xml); + + xml << " \n"; + xml << " \n"; + while (in >> line) + { + xml << " " << XML_Entities(line) << "\n"; + } + xml << " \n"; + xml << " \n"; + xml << "\n"; +} + diff --git a/src/gcm_input/log_filter.h b/src/gcm_input/log_filter.h new file mode 100644 index 0000000..4ad7435 --- /dev/null +++ b/src/gcm_input/log_filter.h @@ -0,0 +1,76 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : log_filter.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Message filter for various kinds of log files. +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 26, 2003 +** LAST UPDATE : Nov 26, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: log_filter.h,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: log_filter.h,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#ifndef LOG_FILTER_H +#define LOG_FILTER_H + +#include "message_filter.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : log_filter +// BASECLASS : message_filter +// MEMBERS : +// OPERATORS : +// METHODS : construct_XML +// +// DESCRIPTION : Transforms a log file into an XML document by putting +// each line of input into a XML element. +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 26, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class log_filter : public message_filter +{ + +protected: + +public: + + log_filter(String host, UTC arriv, String service) : message_filter(host, arriv, service) + { + } + + virtual void construct_XML(message_buffer &in, std::strstream &xml); +}; + +#endif // LOG_FILTER_H diff --git a/src/gcm_input/message.cpp b/src/gcm_input/message.cpp index 1c36a27..7e727ff 100644 --- a/src/gcm_input/message.cpp +++ b/src/gcm_input/message.cpp @@ -8,7 +8,7 @@ *********************** ** FILE NAME : message.cpp ** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring -** VERSION NUMBER : $Revision: 1.15 $ +** VERSION NUMBER : $Revision: 1.16 $ ** ** DESCRIPTION : Implementation of the message handling classes ** @@ -20,13 +20,20 @@ ******************************** ** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl ** CREATION DATE : Sep 16, 2002 -** LAST UPDATE : Jul 24, 2003 +** LAST UPDATE : Nov 28, 2003 ** MODIFICATIONS : **************************************************************************/ /***************************** $Log: message.cpp,v $ - Revision 1.15 2003-10-27 11:28:27 arjen + Revision 1.16 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + + Revision 1.15 2003/10/27 11:28:27 arjen Do not add another parameter_notification record is the notification already exists for that parameter. @@ -90,7 +97,7 @@ *****************************/ -static const char *RCSID = "$Id: message.cpp,v 1.15 2003-10-27 11:28:27 arjen Exp $"; +static const char *RCSID = "$Id: message.cpp,v 1.16 2003-12-04 10:38:09 arjen Exp $"; #include #include @@ -102,7 +109,7 @@ static const char *RCSID = "$Id: message.cpp,v 1.15 2003-10-27 11:28:27 arjen Ex extern bool verbose; /* Defined in the main application */ extern bool testmode; extern bool incremental; -extern std::ostream *log; +extern std::ostream *Log; /* Utility functions */ @@ -151,6 +158,22 @@ bool operator >> (message_buffer &b, String &s) return input_ok; } +/*========================================================================= +** NAME : client_message +** SYNOPSIS : client_message(std::istream *in, gnucomo_database db) +** PARAMETERS : +** RETURN VALUE : None +** +** DESCRIPTION : Client message constructor. +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 04, 2002 +**========================================================================= +*/ + client_message::client_message(std::istream *in, gnucomo_database db) { input.from(in); @@ -164,7 +187,6 @@ client_message::client_message(std::istream *in, gnucomo_database db) certainty = 0.0; } -static const String mail_date_re("[[:alpha:]]{3}, [ 123]?[0-9] [[:alpha:]]{3} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [+-][0-9]{4}"); static const String unix_date_re("[[:alpha:]]{3} [[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}"); static const regex re_PGP("-----BEGIN PGP MESSAGE-----"); @@ -172,48 +194,33 @@ static const regex re_dump("^ *DUMP: Date of this level"); static const regex re_rpm("[[:alnum:]+-]+-[0-9][[:alnum:].-]"); static const regex re_uxmail_from("^From [^ \t]+[ ]+" + unix_date_re); -static const regex re_mail_From("^From:[[:blank:]]+"); -static const regex re_mail_Date("^Date:[[:blank:]]+" + mail_date_re); -static const regex re_mail_MsId("^Message-Id:[[:blank:]]+"); -static const regex re_email_address("[[:alnum:]_.-]+@[[:alnum:]_.-]+"); -static const regex re_email_user("[[:alnum:]_.-]+@"); static const regex re_xml_header("xml .*\?>$"); /*========================================================================= -** NAME : readXMLinput -** SYNOPSIS : int readXMLinput(String first_line) +** NAME : extractHeader +** SYNOPSIS : void extractHeader() ** PARAMETERS : -** RETURN VALUE : Parse the XML input and extract the header information +** RETURN VALUE : True if the mandatory header elements are available. ** -** DESCRIPTION : +** DESCRIPTION : Extract the header information from the XML DOM tree. ** ** VARS USED : ** VARS CHANGED : ** FUNCTIONS USED : ** SEE ALSO : -** LAST MODIFIED : Jul 24, 2003 +** LAST MODIFIED : Nov 26, 2003 **========================================================================= */ -int client_message::readXMLinput(String first_line) +bool client_message::extractHeader() { - xmlParserCtxtPtr ctxt; - String line; xmlNodePtr root, item; xmlNsPtr namespaces[1]; xmlXPathObjectPtr res; xmlXPathContextPtr pathcontext; - - ctxt = xmlCreatePushParserCtxt(NULL, NULL, first_line, ~first_line, NULL); - while (input >> line) - { - xmlParseChunk(ctxt, line, ~line, 0); - } - xmlParseChunk(ctxt, "", 0, 1); - xmlDom = ctxt->myDoc; - xmlFreeParserCtxt(ctxt); + bool header_OK = true; root = xmlDocGetRootElement(xmlDom); namespaces[0] = root->ns; @@ -230,70 +237,73 @@ int client_message::readXMLinput(String first_line) #endif res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:messagetype/text()", pathcontext); - if (res->nodesetval != NULL) + if (res->nodesetval != NULL && res->nodesetval->nodeTab != NULL) { -#ifdef DEBUG - xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0); -#endif item = *res->nodesetval->nodeTab; // Select a line cooker based on the message type. #ifdef DEBUG - std::cout << "Looking for a line cooker for " << item->content << "\n"; + *Log << "Looking for a line cooker for " << item->content << "\n"; #endif - std::list::iterator lci = kitchen.begin(); - pan = 0; - while (pan == 0 && lci != kitchen.end()) + pan.lc = 0; + std::list::iterator lci = kitchen.begin(); + while (pan.lc == 0 && lci != kitchen.end()) { - pan = *lci; - if (pan->message_type() != (const char *)(item->content)) + if (lci->lc->message_type() == (const char *)(item->content)) { - pan = 0; + pan.lc = lci->lc; } lci++; } - if (pan == 0) + if (pan.lc == 0) { - *log << "Can not find a line cooker for message type " << item->content << "\n"; + *Log << "Can not find a line cooker for message type " << item->content << "\n"; + header_OK = false; } } else { - *log << "Message type not found in XML header.\n"; + *Log << "Message type not found in XML header.\n"; + header_OK = false; } res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:hostname/text()", pathcontext); - if (res->nodesetval != NULL) + if (res->nodesetval != NULL && res->nodesetval->nodeTab != NULL) { -#ifdef DEBUG - xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0); -#endif item = *res->nodesetval->nodeTab; hostname = (const char *)item->content; } else { - *log << "Hostname not found in XML header.\n"; + *Log << "Can not determine the hostname where the message came from.\n"; + header_OK = false; } res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:service/text()", pathcontext); - if (res->nodesetval != NULL) + if (res->nodesetval != NULL && res->nodesetval->nodeTab != NULL) { item = *res->nodesetval->nodeTab; service = (const char *)item->content; } res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:time/text()", pathcontext); - if (res->nodesetval != NULL) + if (res->nodesetval != NULL && res->nodesetval->nodeTab != NULL) { item = *res->nodesetval->nodeTab; arrival = String((char *)item->content); + if (!arrival.proper()) + { + *Log << "Arrival time is not properly stated.\n"; + header_OK = false; + } } //xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0); + return header_OK; } + /*========================================================================= ** NAME : classify ** SYNOPSIS : double classify(String host, date arriv_d, hour arriv_t, String serv) @@ -306,7 +316,7 @@ int client_message::readXMLinput(String first_line) ** VARS CHANGED : ** FUNCTIONS USED : ** SEE ALSO : -** LAST MODIFIED : Aug 11, 2003 +** LAST MODIFIED : Nov 27, 2003 **========================================================================= */ @@ -318,6 +328,11 @@ double client_message::classify(String host, UTC arriv, String serv) arrival = arriv; service = serv; + const double epsilon = 0.1; // Threshold for uncertainty + const double P = 0.5; // Probability of a wrong match + + double uncertainty; + /* First, check if the message has a mail header. */ if (input >> line && line == re_uxmail_from) @@ -326,34 +341,10 @@ double client_message::classify(String host, UTC arriv, String serv) mail_header = true; - /* Scan ahead for the hostname and date of arrival. */ + /* Skip the mail header until the first empty line. */ while (input >> line && line != "") { - if (line == re_mail_From) - { - from_address = line(re_email_address); - from_address(re_email_user) = ""; // Remove the user part; - if (from_address != "" && ~hostname < ~from_address) - { - *log << "Detected hostname " << from_address << "\n"; - hostname = from_address; - } - } - if (line == re_mail_MsId) - { - from_address = line(re_email_address); - from_address(re_email_user) = ""; // Remove the user part; - if (from_address != "" && ~hostname < ~from_address) - { - *log << "Detected hostname " << from_address << "\n"; - hostname = from_address; - } - } - if (line == re_mail_Date) - { - arrival = UTC(line(regex(mail_date_re))); - } } } else @@ -363,97 +354,59 @@ double client_message::classify(String host, UTC arriv, String serv) } - pan = 0; - /* * Now that we have the mail header out of the way, try to figure * out what the content of the message is. */ - while (input >> line && certainty < 0.9) + uncertainty = 1.0; + + while (input >> line && uncertainty > 0.1) { if (verbose) { - *log << " testing: " << line << "\n"; + *Log << " testing: " << line << "\n"; } - if (line == re_xml_header) + if (line == re_PGP) { - certainty = 1.0; - classification = XML; - if (verbose) - { - *log << "XML input detected.\n"; - } - readXMLinput(line); - } - else if (line == re_PGP) - { - certainty = 1.0; + uncertainty = 0.0; gpg_encrypted = true; - *log << "The message is PGP/GnuPG encrypted.\n"; - } - else if (line == re_dump) - { - certainty = 1.0; - if (verbose) - { - *log << "DUMP output detected.\n"; - } - } - else if (line == re_rpm) - { - certainty = 1.0; - classification = RPMLIST; - service = ""; - if (verbose) - { - *log << "RPM package list detected.\n"; - } + *Log << "The message is PGP/GnuPG encrypted.\n"; } else { // Scan the list of line cookers if there is anything familiar. - std::list::iterator lci = kitchen.begin(); - pan = 0; - while (pan == 0 && lci != kitchen.end()) + std::list::iterator lci = kitchen.begin(); + uncertainty = 1.0; + while (lci != kitchen.end()) { - pan = *lci; - if (!pan->check_pattern(line)) + if (lci->lc->check_pattern(line)) { - pan = 0; + // We have a match; decrease the uncertainty + + lci->uncertainty *= P; + if (uncertainty > lci->uncertainty) + { + uncertainty = lci->uncertainty; + pan = *lci; + } + if (verbose) + { + *Log << lci->lc->message_type() << " detected with " + << lci->uncertainty << " uncertainty.\n"; + } } lci++; } - if (pan != 0) - { - certainty = 1.0; - classification = COOKER_OBJECT; - if (verbose) - { - *log << "Detected message type " << pan->message_type() << "\n"; - } - } + classification = COOKER_OBJECT; } } input.rewind(); - if (hostname == "") - { - *log << "Can not determine the hostname where the message came from.\n"; - certainty = 0.0; - } - else if (!arrival.proper()) - { - *log << "Arrival time is not known.\n"; - certainty = 0.0; - } - else - { - certainty = 1.0; - } + certainty = 1.0 - uncertainty; return certainty; } @@ -471,12 +424,20 @@ double client_message::classify(String host, UTC arriv, String serv) ** VARS CHANGED : ** FUNCTIONS USED : ** SEE ALSO : -** LAST MODIFIED : Jul 24, 2003 +** LAST MODIFIED : Nov 28, 2003 **========================================================================= */ +struct param_property +{ + String name; + String value; +}; + void client_message::enterXML() { + //TODO : return the number of elements that are handled. + xmlXPathObjectPtr res; xmlXPathContextPtr pathcontext; xmlNsPtr namespaces[1]; @@ -484,16 +445,17 @@ void client_message::enterXML() /* Try to find the host in the database */ String objectid; + String remark; // For notifications objectid = database.find_host(hostname); if (objectid == "") { - *log << "Please define the host " << hostname << " in the database.\n"; + *Log << "Please define the host " << hostname << " in the database.\n"; return; } if (verbose) { - *log << "Object id for " << hostname << " is " << objectid << "\n"; + *Log << "Object id for " << hostname << " is " << objectid << "\n"; } pathcontext = xmlXPathNewContext(xmlDom); @@ -528,29 +490,29 @@ void client_message::enterXML() String raw("");; String log_service; - if (strcmp((char *)node->name, "raw") == 0) + if (strcmp((char *)node->name, "raw") == 0 && node->children != NULL) { item = node->children; - if (pan == 0) + if (pan.lc == 0) { - *log << "Can not cook this type of log element.\n"; + *Log << "Can not cook this type of log element.\n"; } else { raw = String((const char *)item->content); - if (pan->cook_this(raw, arrival)) + if (pan.lc->cook_this(raw, arrival)) { - log_hostname = pan->hostname(); + log_hostname = pan.lc->hostname(); if (log_hostname == "") { log_hostname = hostname; } - log_service = pan->service(); - log_date = pan->timestamp(); + log_service = pan.lc->service(); + log_date = pan.lc->timestamp(); } else { - *log << "Log line " << raw << " does not match.\n"; + *Log << "gcm_input WARNING: Not a valid line: " << raw << "\n"; raw = ""; } } @@ -561,7 +523,7 @@ void client_message::enterXML() if (verbose) { - *log << "Analyzing cooked element.\n"; + *Log << "Analyzing cooked element.\n"; } pathcontext->node = node; @@ -572,7 +534,7 @@ void client_message::enterXML() log_hostname = (const char *)item->content; if (log_hostname != hostname(0, ~log_hostname)) { - *log << "Hostname " << log_hostname << " does not match.\n"; + *Log << "Hostname " << log_hostname << " does not match.\n"; log_hostname = ""; } } @@ -600,7 +562,7 @@ void client_message::enterXML() } else { - *log << " missing from cooked log element.\n"; + *Log << " missing from cooked log element.\n"; } res = xmlXPathEval((const xmlChar *)"raw/text()", pathcontext); @@ -611,7 +573,7 @@ void client_message::enterXML() } else { - *log << " missing from cooked log element.\n"; + *Log << " missing from cooked log element.\n"; } } @@ -633,396 +595,215 @@ void client_message::enterXML() if (testmode) { - *log << insertion << "\n"; + *Log << insertion << "\n"; } else { database.Query(insertion); } - if (verbose) - { - *log << "\n\n"; - } } } node = node->next; } } - else + else if (strcmp((char *)node->name, "parameters") == 0) { - *log << "Data element " << node->name << " is not supported.\n"; - } - } - else - { - *log << "Data node not found.\n"; - } -} + // Each child contains a parameter entry, with at least one property -/*========================================================================= -** NAME : enter -** SYNOPSIS : int enter() -** PARAMETERS : -** RETURN VALUE : The number of lines successfully parsed from the input -** -** DESCRIPTION : -** -** VARS USED : -** VARS CHANGED : -** FUNCTIONS USED : -** SEE ALSO : -** LAST MODIFIED : Jul 24, 2003 -**========================================================================= -*/ - -int client_message::enter() -{ - if (classification == XML) - { - enterXML(); - return 1; - } - - long nr_lines = 0; - String line; - String qry; - - String change_notification(""); - String create_notification(""); - bool initial_entry = false; - - std::list packages; - - - /* Double-check the classification of the message */ - - if (classification == UNKNOWN || certainty < 0.9 || gpg_encrypted) - { - return 0; - } + String qry; + String insertion; + String change_notification(""); + String create_notification(""); + String remove_notification(""); + bool initial_entry = false; + String param_class((const char *)xmlGetProp(node, (const xmlChar *)"class")); - if (mail_header) - { - // Skip the mail header. + pathcontext->node = node; - while (input >> line && line != ""); - } + // If we don;t have any parameters of this class, this will be + // an initial entry. - /* Try to find the host in the database */ - - String objectid; - - objectid = database.find_host(hostname); - if (objectid == "") - { - *log << "Please define the host " << hostname << " in the database.\n"; - return 0; - } - if (verbose) - { - *log << "Object id for " << hostname << " is " << objectid << "\n"; - } - - if (classification == RPMLIST) - { - - int n_packages; - - /* Read all packages, so we will know which ones are */ - /* missing at the end. */ - - qry = "select name from parameter where objectid='"; - qry += objectid + "' and class='package'"; - n_packages = database.Query(qry); - initial_entry = n_packages == 0; - -#ifdef DEBUG - *log << n_packages << " packages in database.\n"; -#endif - for (int t = 0; t < n_packages; t++) - { - packages.push_back(database.Field(t, "name")); - } -#ifdef DEBUG - *log << "Package list built: " << packages.size() << ".\n"; -#endif - } - - /* Scan the input line by line, entring records into the database */ - - String rest; // Rest of the line to be parsed - regex re_any(".*"); - - while (input >> line) - { - if (verbose) - { - *log << line << "\n"; - } + qry = "select name from parameter where objectid='"; + qry += objectid + "' and class='" + param_class + "'"; + initial_entry = database.Query(qry) == 0; + node = node->children; + while (node != NULL) + { + if (node->type == XML_ELEMENT_NODE && + strcmp((char *)node->name, "parameter") == 0) + { + String param_name((const char *)xmlGetProp(node, (const xmlChar *)"name")); - /* Check each line if it contains valid information */ + std::list properties; + param_property prop; + xmlNodePtr item; - const regex *check; + String paramid; - switch (classification) - { - case RPMLIST: - check = &re_rpm; - break; - case COOKER_OBJECT: - check = &re_any; - break; - } - if (line == *check) - { - date log_date; - hour log_time; - int i; + // Collect the parameter's properties. - String insertion("insert into log (objectid, servicecode," - " object_timestamp, timestamp, rawdata, processed) values ("); - String datestring; - - switch (classification) - { - case COOKER_OBJECT: -#ifdef DEBUG - std::cerr << "\ncooker check: " << pan->check_pattern(line) << "\n"; -#endif - if (pan->cook_this(line, arrival)) - { - if (pan->hostname() == hostname(0,~pan->hostname())) + item = node->children; + while (item != NULL) { - -#ifdef DEBUG - std::cerr << " Information from cooker:\n"; - std::cerr << " timestamp = " << pan->timestamp() << "\n"; - std::cerr << " hostname = " << pan->hostname() << "\n"; - std::cerr << " service = " << pan->service() << "\n"; -#endif - /* Insert a new record into the log table */ - - insertion += "'" + objectid + "',"; - insertion += "'" + pan->service() + "',"; - insertion += "'" + pan->timestamp().format("%Y-%m-%d %T") + "',"; - insertion += "'" + arrival.format("%Y-%m-%d %T") + "',"; - insertion += "'" + SQL_Escape(line) + "',FALSE"; - insertion += ")"; - - if (testmode) + if (item->type == XML_ELEMENT_NODE && + strcmp((char *)item->name, "property") == 0) { - *log << insertion << "\n"; - } - else - { - database.Query(insertion); + prop.name = (const char *)xmlGetProp(item, (const xmlChar *)"name"); + if (item->children != NULL) + { + prop.value = (const char *)item->children->content; + properties.push_back(prop); + } + else + { + *Log << "WARNING: Property " << prop.name << " has no value.\n"; + } } - if (verbose) - { - *log << "\n\n"; - } + // TODO: Hanlde description element - nr_lines++; + item = item->next; } - else - { - *log << " Hostname " << pan->hostname() << " does not match.\n"; - } - } - else - { - *log << "gcm_input WARNING: Not a valid line: " << line << "\n"; - } - break; - - case RPMLIST: - // Scan a list of packages and versions from "rpm -a". - // A similar listing can be created on IRIX 6.5 by using the - // command "showprods -3 -n|awk '{printf "%s-%s\n",$2,$3}'|grep -v '^[-=]' \ - // |grep -v Version-Description". - // - // We have to separate the package name and the version. - // The separation is marked by a '-', followed by a digit. - // However, there may be other sequences of '-'digit in the package name, - // do we have to scan ahead until there is at most one such sequence - // left in the version string. The '-'digit seqeunce inside the - // version usually separates the version and the release number. + // Check the parameter in the database. - int version_start, next_version_start; + std::list::iterator pi = properties.begin(); - i = line.index('-'); - version_start = i; - next_version_start = i; + qry = "select paramid from parameter where objectid='"; + qry += objectid + "' and class='"; + qry += param_class + "' and name='"; + qry += param_name + "'"; - while (i < ~line - 1) - { - while (i < ~line - 1 && !(line[i] == '-' && isdigit(line[i + 1]))) - { - i++; - } - if (i < ~line - 1) + if (database.Query(qry) == 1) { - version_start = next_version_start; - next_version_start = i; - } - i++; - } - - if (!isdigit(line[version_start + 1])) - { - version_start = next_version_start; - } - String package(line(0,version_start)); - String version(line(version_start + 1, ~line)); - String paramid; - String remark; - String insert_h; + // The parameter exists in the database; check all properties. - if (verbose) - { - *log << "Package is " << package; - *log << ", version is " << version << "\n"; - } + bool param_changed = false; - // Construct a qry to check the package's existance + paramid = database.Field(0, "paramid"); + while (pi != properties.end()) + { + qry = "select value from property where paramid='"; + qry += paramid + "' and name='"; + qry += pi->name + "'"; + if (database.Query(qry) == 0) + { + *Log << "Property " << pi->name << " of " + << param_name << " does not exist.\n"; + } + else if (database.Field(0, "value") != pi->value) + { + *Log << "Property " << pi->name << " of " + << param_name << " is different.\n"; - qry = "select paramid from parameter where objectid='"; - qry += objectid + "' and class='package' and name='"; - qry += package + "'"; + insertion = "update property set value='"; + insertion += pi->value + "' where paramid='"; + insertion += paramid + "' and name='"; + insertion += pi->name + "'"; - if (database.Query(qry) == 1) - { - std::list::iterator lp; + database.Query(insertion); - lp = find(packages.begin(), packages.end(), package); - if (lp != packages.end()) - { - packages.erase(lp); - } - else - { - *log << "Could NOT find " << package << " in list.\n"; - } + insertion = "insert into history (paramid, modified,"; + insertion += " change_nature, changed_property, new_value)"; + insertion += " values ('"; + insertion += paramid + "', '" + arrival.format("%Y-%m-%d %T") + + "', 'MODIFIED', '"; + insertion += pi->name + "', '"; + insertion += pi->value + "')"; - paramid = database.Field(0, "paramid"); - qry = "select value from property where paramid='"; - qry += paramid + "' and name='version'"; - if (database.Query(qry) == 0) - { - *log << "Database corruption: Package " << package; - *log << " does not have a 'version' property.\n"; - } - else if (database.Field(0, "value") != version) - { - if (verbose) - { - *log << " Parameter " << package << " has different version\n"; - } - insertion = "update property set value='"; - insertion += version + "' where paramid='"; - insertion += paramid + "' and name='version'"; + database.Query(insertion); - insert_h = "insert into history (paramid, modified, change_nature, changed_property, new_value)"; - insert_h += " values ('"; - insert_h += paramid + "', '" + arrival.format("%Y-%m-%d %T") + "', 'MODIFIED', 'version', '"; - insert_h += version + "')"; + param_changed = true; - database.Query(insertion); - database.Query(insert_h); - if (change_notification == "") - { - remark = "Gnucomo detected a different version for package parameter(s) "; - change_notification = database.new_notification(objectid, "property modified", remark); - change_notification = database.new_notification(objectid, "property modified", remark); + } + pi++; } - if (change_notification != "") + if (param_changed) { - qry = "select * from parameter_notification where notificationid='"; - qry += change_notification + "' and paramid='"; - qry += paramid + "'"; + if (change_notification == "") + { + remark = "Gnucomo detected a different version for package parameter(s) "; + change_notification = database.new_notification(objectid, + "property modified", remark); + } - if (database.Query(qry) == 0) + if (change_notification != "") { - insertion = "insert into parameter_notification (notificationid, paramid) values ('"; - insertion += change_notification + "', '"; - insertion += paramid + "')"; + qry = "select * from parameter_notification where notificationid='"; + qry += change_notification + "' and paramid='"; + qry += paramid + "'"; - database.Query(insertion); + if (database.Query(qry) == 0) + { + insertion = "insert into parameter_notification"; + insertion += " (notificationid, paramid) values ('"; + insertion += change_notification + "', '"; + insertion += paramid + "')"; + + database.Query(insertion); + } + } + else + { + *Log << "gcm_input ERROR: Cannot create 'property modified' notification.\n"; } - } - else - { - *log << "gcm_input ERROR: Cannot create 'property modified' notification.\n"; } } else { - if (verbose) - { - *log << " Parameter " << package << " has not changed.\n"; - } - } - } - else - { + // The parameter does not exist; create anew. - if (verbose) - { - *log << " Parameter " << package << " does not exist.\n"; - } - // Create a new package parameter, including version property and history record + // TODO: Insert description - insertion = "insert into parameter (objectid, name, class, description) values ('"; - insertion += objectid + "', '" + package + "', 'package', 'RPM package " + package + "')"; - if (testmode) - { - paramid = "0"; - *log << insertion << "\n"; - } - else - { + insertion = "insert into parameter (objectid, name, class, description) values ('"; + insertion += objectid + "', '" + param_name + "', '" + param_class + "', '')"; database.Query(insertion); + qry = "select paramid from parameter where objectid='"; - qry += objectid + "' and class='package' and name='"; - qry += package + "'"; + qry += objectid + "' and class='"; + qry += param_class + "' and name='"; + qry += param_name + "'"; database.Query(qry); paramid = database.Field(0, "paramid"); - } - insertion = "insert into property (paramid, name, value, type) values ('"; - insertion += paramid + "', 'version', '"; - insertion += version + "', 'STATIC')"; - insert_h = "insert into history (paramid, modified, change_nature, changed_property, new_value)"; - insert_h += " values ('"; - insert_h += paramid + "', '" + arrival.format("%Y-%m-%d %T") + "', 'CREATED', 'version', '"; - insert_h += version + "')"; + while (pi != properties.end()) + { + insertion = "insert into property (paramid, name, value, type) values ('"; + insertion += paramid + "', '"; + insertion += pi->name + "', '"; + insertion += pi->value + "', 'STATIC')"; + database.Query(insertion); + + insertion = "insert into history (paramid, modified,"; + insertion += " change_nature, changed_property, new_value)"; + insertion += " values ('"; + insertion += paramid + "', '" + arrival.format("%Y-%m-%d %T") + + "', 'CREATED', '"; + insertion += pi->name + "', '"; + insertion += pi->value + "')"; + database.Query(insertion); + + pi++; + } - if (testmode) - { - *log << insertion << "\n" << insert_h << "\n"; - } - else - { - database.Query(insertion); - database.Query(insert_h); if (!initial_entry) { if (create_notification == "") { remark = "Gnucomo detected new parameter(s) of class package"; - create_notification = database.new_notification(objectid, "parameter created", remark); + create_notification = database.new_notification(objectid, + "parameter created", remark); } if (create_notification != "") { - insertion = "insert into parameter_notification (notificationid, paramid) values ('"; + insertion = "insert into parameter_notification"; + insertion += " (notificationid, paramid) values ('"; insertion += create_notification + "', '"; insertion += paramid + "')"; @@ -1030,98 +811,138 @@ int client_message::enter() } else { - *log << "gcm_input ERROR: Cannot create 'parameter created' notification.\n"; + *Log << "gcm_input ERROR: Cannot create 'parameter created' notification.\n"; } } } } - if (verbose) - { - *log << "\n"; - } - - nr_lines++; - break; - + node = node->next; } - } - else - { - *log << "gcm_input WARNING: Not a valid line: " << line << "\n"; - } - } - if (classification == RPMLIST && !incremental) - { - std::list::iterator lp; - String remove_notification(""); + if (!incremental) + { + // Check if any parameters in this class have disappeared. - /* - * If there are any packages left in the list, they seem to have - * disappeared from the system. - */ + qry = "select name, paramid from parameter where objectid='"; + qry += objectid + "' and class='" + param_class + "'"; - for (lp = packages.begin(); lp != packages.end(); lp++) - { - String paramid; - String remark; - String insert; + int nr_parameters = database.Query(qry); + pqxx::Result parameter_set = database.Result(); - // Construct a qry to check the package's existance + for (int i = 0; i < nr_parameters; i++) + { + String XPath; + String param_name, paramid; - qry = "select paramid from parameter where objectid='"; - qry += objectid + "' and class='package' and name='"; - qry += *lp + "'"; + param_name = database.Field(parameter_set, i, "name"); + XPath = "gcmt:parameter[@name='" + param_name + "']"; - if (database.Query(qry) == 1) - { - paramid = database.Field(0, "paramid"); - qry ="select change_nature from history where paramid='"; - qry += paramid + "' order by modified desc"; - if (database.Query(qry) <= 0) - { - *log << "Database ERROR: no history record for parameter " << *lp << ".\n"; - } - else if (database.Field(0, "change_nature") != "REMOVED") - { - if (verbose) + res = xmlXPathEval((const xmlChar *)(const char *)XPath, pathcontext); + if (res->nodesetval->nodeTab == NULL) { - *log << "Removing parameter " << *lp << ".\n"; - } + // The parameter is in the database but not in the report - insert = "insert into history (paramid, modified, change_nature)"; - insert += " values ('"; - insert += paramid + "', '" + arrival.format("%Y-%m-%d %T") + "', 'REMOVED')"; + paramid = database.Field(parameter_set, i, "paramid"); + qry ="select change_nature from history where paramid='"; + qry += paramid + "' order by modified desc"; + if (database.Query(qry) <= 0) + { + *Log << "Database ERROR: no history record for parameter " + << param_name << ".\n"; + } + else if (database.Field(0, "change_nature") != "REMOVED") + { + if (verbose) + { + *Log << "Removing parameter " << param_name << ".\n"; + } - database.Query(insert); + insertion = "insert into history (paramid, modified, change_nature)"; + insertion += " values ('"; + insertion += paramid + "', '" + arrival.format("%Y-%m-%d %T") + + "', 'REMOVED')"; - if (remove_notification == "") - { - remark = "Gnucomo detected that package(s) have disappeared "; - remove_notification = database.new_notification(objectid, "parameter removed", remark); - } + database.Query(insertion); - if (remove_notification != "") - { - insert = "insert into parameter_notification (notificationid, paramid) values ('"; - insert += remove_notification + "', '"; - insert += paramid + "')"; + if (remove_notification == "") + { + remark = "Gnucomo detected that package(s) have disappeared "; + remove_notification = database.new_notification(objectid, + "parameter removed", remark); + } - database.Query(insert); - } - else - { - *log << "gcm_input ERROR: Cannot create 'parameter removed' notification.\n"; + if (remove_notification != "") + { + insertion = "insert into parameter_notification"; + insertion += " (notificationid, paramid) values ('"; + insertion += remove_notification + "', '"; + insertion += paramid + "')"; + + database.Query(insertion); + } + else + { + *Log << "gcm_input ERROR: Cannot create 'parameter removed' notification.\n"; + } + } } } } } + else + { + *Log << "Data element " << node->name << " is not supported.\n"; + } } + else + { + *Log << "Data node not found.\n"; + } +} - if (verbose) +/*========================================================================= +** NAME : enter +** SYNOPSIS : int enter() +** PARAMETERS : +** RETURN VALUE : The number of lines successfully parsed from the input +** +** DESCRIPTION : +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 26, 2003 +**========================================================================= +*/ + +int client_message::enter() +{ + pan.mf->set_message_type(pan.lc->message_type()); + + pan.mf->construct_XML(input, xmlBuffer); + +#ifdef DEBUG + *Log << "Constructed XML document:\n\n"; + *Log << xmlBuffer.str(); + *Log << "\n"; +#endif + + xmlDom = xmlParseMemory(xmlBuffer.str(), xmlBuffer.pcount()); + + if (xmlDom) + { + if (extractHeader()) + { + enterXML(); + } + } + else { - *log << nr_lines << " lines parsed from the log file.\n"; + *Log << "XML parser FAILED.\n"; } - return nr_lines; + + return 0; + } diff --git a/src/gcm_input/message.h b/src/gcm_input/message.h index eb32449..723aabd 100644 --- a/src/gcm_input/message.h +++ b/src/gcm_input/message.h @@ -8,7 +8,7 @@ *********************** ** FILE NAME : message.h ** SYSTEM NAME : -** VERSION NUMBER : $Revision: 1.7 $ +** VERSION NUMBER : $Revision: 1.8 $ ** ** DESCRIPTION : Classes to for handling client messages ** @@ -26,7 +26,14 @@ /***************************** $Log: message.h,v $ - Revision 1.7 2003-08-11 16:56:16 arjen + Revision 1.8 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + + Revision 1.7 2003/08/11 16:56:16 arjen Different kinds of log files are parsed by a collection of objects of different classes, derived from the base class line_cooker Depending on the message content or the message_type element in @@ -61,7 +68,7 @@ *****************************/ -/* static const char *RCSID = "$Id: message.h,v 1.7 2003-08-11 16:56:16 arjen Exp $"; */ +/* static const char *RCSID = "$Id: message.h,v 1.8 2003-12-04 10:38:09 arjen Exp $"; */ #include #include @@ -70,72 +77,30 @@ #include +#include "message_filter.h" #include "line_cooker.h" #include "database.h" -/* -/////////////////////////////////////////////////////////////////////////// -// NAME : message_buffer -// BASECLASS : -// MEMBERS : -// OPERATORS : -// METHODS : rewind() -// -// DESCRIPTION : -// -// RELATIONS : -// SEE ALSO : -// LAST MODIFIED : Nov 04, 2002 -/////////////////////////////////////////////////////////////////////////// -*/ +// Associates line cookers and message filters -class message_buffer +struct xform { - std::istream *input; - std::list buffer; - - std::list::iterator next_line; - -public: + message_filter *mf; + line_cooker *lc; + double uncertainty; - message_buffer() + xform() { - input = 0; - next_line = buffer.begin(); + mf = NULL; + lc = NULL; + uncertainty = 1.0; } - message_buffer(std::istream *in) + xform(message_filter *m, line_cooker *l) { - input = in; - next_line = buffer.begin(); - } - - void from(std::istream *in) - { - input = in; - } - - friend bool operator >> (message_buffer &, String &); - - void rewind() - { - next_line = buffer.begin(); - } - - void operator ++() - { - if (next_line != buffer.end()) - { - next_line++; - } - } - - void operator --() - { - if (next_line != buffer.begin()) - { - next_line--; - } + mf = m; + lc = l; + uncertainty = 1.0; } }; @@ -162,13 +127,14 @@ class client_message UTC arrival; // When we got the message. String service; // Service that created the message - std::list kitchen; // The collection of line cookers - line_cooker * pan; // The one we cook this log with + std::list kitchen; // The collection of message filters and line cookers + xform pan; // The one we cook this log with bool mail_header; // Does the message contain a mail header ? bool gpg_encrypted; // Is the message encrypted ? - xmlDocPtr xmlDom; + std::strstream xmlBuffer; + xmlDocPtr xmlDom; double certainty; // How certain are we about the message enum @@ -180,16 +146,18 @@ class client_message message_buffer input; gnucomo_database database; - int readXMLinput(String first_line); void enterXML(); + bool extractHeader(); public: client_message(std::istream *in, gnucomo_database db); - void add_cooker(line_cooker *lc) + void add_cooker(line_cooker *lc, message_filter *mf) { - kitchen.push_back(lc); + xform x(mf, lc); + + kitchen.push_back(x); } double classify(String host, UTC arrival = Now(), String serv = ""); diff --git a/src/gcm_input/message_buffer.h b/src/gcm_input/message_buffer.h new file mode 100644 index 0000000..2a495cd --- /dev/null +++ b/src/gcm_input/message_buffer.h @@ -0,0 +1,111 @@ + +/************************************************************************** +** (c) Copyright 2002, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : message_buffer.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Classes to for buffering the input stream +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Sep 16, 2002 +** LAST UPDATE : Aug 06, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: message_buffer.h,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: message_buffer.h,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include +#include +#include + + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : message_buffer +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : from() +// rewind() +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 04, 2002 +/////////////////////////////////////////////////////////////////////////// +*/ + +class message_buffer +{ + std::istream *input; + std::list buffer; + + std::list::iterator next_line; + +public: + + message_buffer() + { + input = 0; + next_line = buffer.begin(); + } + + message_buffer(std::istream *in) + { + input = in; + next_line = buffer.begin(); + } + + void from(std::istream *in) + { + input = in; + } + + friend bool operator >> (message_buffer &, String &); + + void rewind() + { + next_line = buffer.begin(); + } + + void operator ++() + { + if (next_line != buffer.end()) + { + next_line++; + } + } + + void operator --() + { + if (next_line != buffer.begin()) + { + next_line--; + } + } +}; + diff --git a/src/gcm_input/message_filter.cpp b/src/gcm_input/message_filter.cpp new file mode 100644 index 0000000..02a5978 --- /dev/null +++ b/src/gcm_input/message_filter.cpp @@ -0,0 +1,174 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : message_filter.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 26, 2003 +** LAST UPDATE : Nov 26, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: message_filter.cpp,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: message_filter.cpp,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include "message_filter.h" + +extern std::ostream *Log; + +/*========================================================================= +** NAME : constructXML +** SYNOPSIS : int constructXML(message_buffer &in, std::strstream &xml) +** PARAMETERS : +** RETURN VALUE : +** +** DESCRIPTION : Copy the input stream into the internal XML buffer +** The input is already in XML format, so no real transformation +** is needed. +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 26, 2003 +**========================================================================= +*/ + +void message_filter::construct_XML(message_buffer &in, std::strstream &xml) +{ + String line; + + while (in >> line) + { + xml << line << "\n"; + } +} + +static const String mail_date_re("[[:alpha:]]{3}, [ 123]?[0-9] [[:alpha:]]{3} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [+-][0-9]{4}"); +static const String unix_date_re("[[:alpha:]]{3} [[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}"); +static const regex re_uxmail_from("^From [^ \t]+[ ]+" + unix_date_re); +static const regex re_mail_From("^From:[[:blank:]]+"); +static const regex re_mail_Date("^Date:[[:blank:]]+" + mail_date_re); +static const regex re_mail_MsId("^Message-Id:[[:blank:]]+"); +static const regex re_email_address("[[:alnum:]_.-]+@[[:alnum:]_.-]+"); +static const regex re_email_user("[[:alnum:]_.-]+@"); + +/*========================================================================= +** NAME : scan_email_header +** SYNOPSIS : void scan_email_header(message_buffer &in) +** PARAMETERS : +** RETURN VALUE : +** +** DESCRIPTION : +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 26, 2003 +**========================================================================= +*/ + +void message_filter::scan_email_header(message_buffer &in) +{ + String line; + + /* First, check if the message has a mail header. */ + + if (in >> line && line == re_uxmail_from) + { + String from_address; + + /* Scan ahead for the hostname and date of arrival. */ + + while (in >> line && line != "") + { + + if (line == re_mail_From) + { + from_address = line(re_email_address); + from_address(re_email_user) = ""; // Remove the user part; + if (from_address != "" && ~hn < ~from_address) + { + *Log << "Detected hostname " << from_address << "\n"; + hn = from_address; + } + } + if (line == re_mail_MsId) + { + from_address = line(re_email_address); + from_address(re_email_user) = ""; // Remove the user part; + if (from_address != "" && ~hn < ~from_address) + { + *Log << "Detected hostname " << from_address << "\n"; + hn = from_address; + } + } + if (line == re_mail_Date) + { + ts = UTC(line(regex(mail_date_re))); + } + } + } + else + { + // Push the first line back, we need to read it again. + --in; + + } + +} + +/*========================================================================= +** NAME : construct_header +** SYNOPSIS : void construct_header(std::strstream &xml) +** PARAMETERS : +** RETURN VALUE : +** +** DESCRIPTION : Create the header for a Gnucomo XML document. +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 26, 2003 +**========================================================================= +*/ + +void message_filter::construct_header(std::strstream &xml) +{ + //xml << "\n"; + xml << "\n"; + xml << "\n"; + xml << " \n"; + xml << " " << mt << "\n"; + xml << " " << hn << "\n"; + xml << " " << srv << "\n"; + xml << " " << ts << "\n"; + xml << " \n"; +} diff --git a/src/gcm_input/message_filter.h b/src/gcm_input/message_filter.h new file mode 100644 index 0000000..65c4090 --- /dev/null +++ b/src/gcm_input/message_filter.h @@ -0,0 +1,98 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : message_filter.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 26, 2003 +** LAST UPDATE : Nov 26, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: message_filter.h,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: message_filter.h,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#ifndef MESSAGE_FILTER_H +#define MESSAGE_FILTER_H + +#include + +#include +#include + +#include "message_buffer.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : message_filter +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : contruct_XML +// set_message_type +// +// DESCRIPTION : Transform any kind of input into an XML document +// for Gnucomo +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 26, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class message_filter +{ + +protected: + + UTC ts; // the timestamp. + String hn; // the hostname + String srv; // the service + String mt; // the message type + + void scan_email_header(message_buffer &in); + void construct_header(std::strstream &xml); + +public: + + message_filter(String host, UTC arriv, String service) + { + hn = host; + ts = arriv; + srv = service; + } + + virtual void construct_XML(message_buffer &in, std::strstream &xml); + + void set_message_type(String msgt) + { + mt = msgt; + } +}; + +#endif // MESSAGE_FILTER_H diff --git a/src/gcm_input/rpm_filter.cpp b/src/gcm_input/rpm_filter.cpp new file mode 100644 index 0000000..dd8655d --- /dev/null +++ b/src/gcm_input/rpm_filter.cpp @@ -0,0 +1,134 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : rpm_filter.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Transform a list of packages into a Gnucomo XML document +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 27, 2003 +** LAST UPDATE : Nov 27, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: rpm_filter.cpp,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: rpm_filter.cpp,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include + +#include "rpm_filter.h" + +/*========================================================================= +** NAME : constructXML +** SYNOPSIS : int constructXML(message_buffer &in, strstream &xml) +** PARAMETERS : +** RETURN VALUE : Create an XML document from a list of RPMs +** +** DESCRIPTION : +** Scan a list of packages and versions from "rpm -a". +** A similar listing can be created on IRIX 6.5 by using the +** command "showprods -3 -n|awk '{printf "%s-%s\n",$2,$3}'|grep -v '^[-=]' \ +** |grep -v Version-Description". +** +** We have to separate the package name and the version. +** The separation is marked by a '-', followed by a digit. +** However, there may be other sequences of '-'digit in the package name, +** do we have to scan ahead until there is at most one such sequence +** left in the version string. The '-'digit seqeunce inside the +** version usually separates the version and the release number. +** +** VARS USED : +** VARS CHANGED : +** FUNCTIONS USED : +** SEE ALSO : +** LAST MODIFIED : Nov 27, 2003 +**========================================================================= +*/ + +void rpm_filter::construct_XML(message_buffer &in, std::strstream &xml) +{ + String line; + + scan_email_header(in); + construct_header(xml); + + xml << " \n"; + xml << " \n"; + + while (in >> line) + { + int version_start, next_version_start; + int i; + + // Separate the package name from the version number + + i = line.index('-'); + version_start = i; + next_version_start = i; + + while (i < ~line - 1) + { + while (i < ~line - 1 && !(line[i] == '-' && isdigit(line[i + 1]))) + { + i++; + } + if (i < ~line - 1) + { + version_start = next_version_start; + next_version_start = i; + } + i++; + } + + if (!isdigit(line[version_start + 1])) + { + version_start = next_version_start; + } + String package(line(0,version_start)); + String version(line(version_start + 1, ~line)); + + // Create the XML element. + + xml << " \n"; + xml << " " << version << "\n"; + xml << " \n"; + } + xml << " \n"; + xml << " \n"; + xml << "\n"; +} + +static const regex re_rpm("[[:alnum:]+-]+-[0-9][[:alnum:].-]"); + +bool rpm_cooker::check_pattern(String logline) +{ + return logline == re_rpm; +} + +bool rpm_cooker::cook_this(String logline, UTC arrival) +{ + return true; +} diff --git a/src/gcm_input/rpm_filter.h b/src/gcm_input/rpm_filter.h new file mode 100644 index 0000000..3450522 --- /dev/null +++ b/src/gcm_input/rpm_filter.h @@ -0,0 +1,109 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : rpm_filter.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 27, 2003 +** LAST UPDATE : Nov 27, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: rpm_filter.h,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: rpm_filter.h,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include "message_filter.h" +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : rpm_filter +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 27, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class rpm_filter : public message_filter +{ + +protected: + +public: + + rpm_filter(String host, UTC arriv, String service) : message_filter(host, arriv, service) + { + } + + virtual void construct_XML(message_buffer &in, std::strstream &xml); +}; + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : rpm_cooker +// BASECLASS : +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 27, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class rpm_cooker : public line_cooker +{ + +protected: + + +public: + + rpm_cooker() + { + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "package list"; + } + +}; diff --git a/src/gcm_input/xml_cooker.cpp b/src/gcm_input/xml_cooker.cpp new file mode 100644 index 0000000..f532f95 --- /dev/null +++ b/src/gcm_input/xml_cooker.cpp @@ -0,0 +1,69 @@ + +/************************************************************************** +** (c) Copyright 2002, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : xml_cooker.cpp +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : Detect whether the input stream is in XML format +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Aug 06, 2003 +** LAST UPDATE : Aug 06, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: xml_cooker.cpp,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: xml_cooker.cpp,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include + +#include "xml_cooker.h" + +static const regex re_xml_header("xml .*\?>$"); + +bool xml_cooker::check_pattern(String logline) +{ + if (XML_detected) + { + return true; + } + else if (logline == re_xml_header) + { + XML_detected = true; + return true; + } + else + { + return false; + } +} + +bool xml_cooker::cook_this(String logline, UTC arrival) +{ + + return true; +} + + diff --git a/src/gcm_input/xml_cooker.h b/src/gcm_input/xml_cooker.h new file mode 100644 index 0000000..7b36936 --- /dev/null +++ b/src/gcm_input/xml_cooker.h @@ -0,0 +1,79 @@ + +/************************************************************************** +** (c) Copyright 2003, Andromeda Technology & Automation +** This is free software; you can redistribute it and/or modify it under the +** terms of the GNU General Public License, see the file COPYING. +*************************************************************************** +** MODULE INFORMATION * +*********************** +** FILE NAME : xml_cooker.h +** SYSTEM NAME : +** VERSION NUMBER : $Revision: 1.1 $ +** +** DESCRIPTION : The XML cooker does not cook anything. It is here to +** match the XML header. +** +** EXPORTED OBJECTS : +** LOCAL OBJECTS : +** MODULES USED : +*************************************************************************** +** ADMINISTRATIVE INFORMATION * +******************************** +** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl +** CREATION DATE : Nov 26, 2003 +** LAST UPDATE : Nov 26, 2003 +** MODIFICATIONS : +**************************************************************************/ + +/***************************** + $Log: xml_cooker.h,v $ + Revision 1.1 2003-12-04 10:38:09 arjen + Major redesign. All input is handled through XML. Raw input data is first + transformed into an XML document for further processing. + A collection of polymorphic classes handle the transformation of various + input formats into XML. + Classifying input data is done with a finite improbability calculation. + +*****************************/ + +/* static const char *RCSID = "$Id: xml_cooker.h,v 1.1 2003-12-04 10:38:09 arjen Exp $"; */ + +#include "line_cooker.h" + +/* +/////////////////////////////////////////////////////////////////////////// +// NAME : xml_cooker +// BASECLASS : line_cooker +// MEMBERS : +// OPERATORS : +// METHODS : +// +// DESCRIPTION : +// +// RELATIONS : +// SEE ALSO : +// LAST MODIFIED : Nov 26, 2003 +/////////////////////////////////////////////////////////////////////////// +*/ + +class xml_cooker : public line_cooker +{ + + bool XML_detected; + +public: + + xml_cooker() + { + XML_detected = false; + } + + bool check_pattern(String logline); + bool cook_this(String logline, UTC arrival); + + String message_type() + { + return "XML"; + } + +}; -- 2.11.0