11package com .acuity .iot .dsa .dslink .sys .logging ;
22
3+ import java .io .PrintWriter ;
4+ import java .io .StringWriter ;
35import java .util .LinkedList ;
46import java .util .List ;
57import java .util .logging .Handler ;
8+ import java .util .logging .Level ;
69import java .util .logging .LogRecord ;
710import java .util .logging .Logger ;
811import org .iot .dsa .dslink .Action .ResultsType ;
1720import org .iot .dsa .node .DSString ;
1821import org .iot .dsa .node .action .DSAction ;
1922import org .iot .dsa .node .action .DSIActionRequest ;
23+ import org .iot .dsa .time .DSDateTime ;
2024
2125/**
2226 * @author Daniel Shapiro
@@ -25,36 +29,51 @@ public abstract class StreamableLogNode extends DSNode {
2529
2630 private static DSList levelRange ;
2731
28- public abstract DSInfo getLevelInfo ();
32+ public abstract DSInfo <?> getLevelInfo ();
2933
3034 public abstract Logger getLoggerObj ();
3135
32- protected DSAction getStreamLogAction () {
36+ protected DSAction getStreamLogAction (boolean isRoot ) {
3337 DSAction act = new DSAction () {
3438 @ Override
3539 public ActionResults invoke (DSIActionRequest req ) {
3640 return ((StreamableLogNode ) req .getTarget ()).startLogStream (req );
3741 }
3842 };
43+ if (isRoot ) {
44+ act .addParameter ("Log Name" , DSString .NULL , "Optional log name to filter by" );
45+ }
46+ act .addDefaultParameter ("Log Level" , DSLevel .ALL , "Log level filter" );
3947 act .addParameter ("Filter" , DSString .NULL , "Optional regex filter" );
4048 act .setResultsType (ResultsType .STREAM );
41- act .addColumnMetadata ("Log" , DSString .NULL ).setEditor ("textarea" );
49+ act .addColumnMetadata ("Timestamp" , DSDateTime .NULL );
50+ act .addColumnMetadata ("Log Name" , DSString .NULL );
51+ act .addColumnMetadata ("Level" , DSLevel .ALL );
52+ act .addColumnMetadata ("Message" , DSString .NULL ).setEditor ("textarea" );
4253 return act ;
4354 }
4455
4556 private ActionResults startLogStream (final DSIActionRequest req ) {
4657 final Logger loggerObj = getLoggerObj ();
58+ final String name = req .getParameters ().getString ("Log Name" );
59+ final DSLevel level = DSLevel .make (req .getParameters ().getString ("Log Level" ));
4760 final String filter = req .getParameters ().getString ("Filter" );
48- final List <String > lines = new LinkedList <>();
61+ final List <DSList > lines = new LinkedList <>();
4962 final Handler handler = new DSLogHandler () {
5063 @ Override
5164 protected void write (LogRecord record ) {
52- String line = toString (this , record );
53- if (filter == null || line .matches (filter )) {
65+ String recordName = record .getLoggerName ();
66+ Level recordLevel = record .getLevel ();
67+ String recordMsg = encodeLogRecord (record );
68+ DSDateTime ts = DSDateTime .valueOf (record .getMillis ());
69+ if (levelMatches (recordLevel , level .toLevel ()) &&
70+ (name == null || name .isEmpty () || name .equals (recordName )) &&
71+ (filter == null || filter .isEmpty () || recordMsg .matches (filter ))) {
72+
5473 while (lines .size () > 1000 ) {
5574 lines .remove (0 );
5675 }
57- lines .add (line );
76+ lines .add (DSList . valueOf ( ts . toString (), recordName , DSLevel . valueOf ( recordLevel ). toString (), recordMsg ) );
5877 req .sendResults ();
5978 }
6079 }
@@ -63,17 +82,25 @@ protected void write(LogRecord record) {
6382 return new ActionResults () {
6483 @ Override
6584 public int getColumnCount () {
66- return 1 ;
85+ return 4 ;
6786 }
6887
6988 @ Override
7089 public void getColumnMetadata (int idx , DSMap bucket ) {
71- new DSMetadata (bucket ).setName ("Record" ).setType (DSString .NULL );
90+ if (idx == 0 ) {
91+ new DSMetadata (bucket ).setName ("Timestamp" ).setType (DSDateTime .NULL );
92+ } else if (idx == 1 ) {
93+ new DSMetadata (bucket ).setName ("Log Name" ).setType (DSString .NULL );
94+ } else if (idx == 2 ) {
95+ new DSMetadata (bucket ).setName ("Level" ).setType (DSLevel .ALL );
96+ } else if (idx == 3 ) {
97+ new DSMetadata (bucket ).setName ("Message" ).setType (DSString .NULL );
98+ }
7299 }
73100
74101 @ Override
75102 public void getResults (DSList bucket ) {
76- bucket .add ( DSString . valueOf ( lines .remove (0 ) ));
103+ bucket .addAll ( lines .remove (0 ));
77104 }
78105
79106 @ Override
@@ -93,6 +120,44 @@ public void onClose() {
93120 }
94121 };
95122 }
123+
124+ private static String encodeLogRecord (LogRecord record ) {
125+ StringBuilder builder = new StringBuilder ();
126+ // class
127+ if (record .getSourceClassName () != null ) {
128+ builder .append (record .getSourceClassName ());
129+ builder .append (" - " );
130+ }
131+ // method
132+ if (record .getSourceMethodName () != null ) {
133+ builder .append (record .getSourceMethodName ());
134+ builder .append (" - " );
135+ }
136+ // message
137+ String msg = record .getMessage ();
138+ if ((msg != null ) && (msg .length () > 0 )) {
139+ Object [] params = record .getParameters ();
140+ if (params != null ) {
141+ msg = String .format (msg , params );
142+ }
143+ builder .append (msg );
144+ }
145+ // exception
146+ Throwable thrown = record .getThrown ();
147+ if (thrown != null ) {
148+ builder .append ("\n " );
149+ StringWriter sw = new StringWriter ();
150+ PrintWriter pw = new PrintWriter (sw );
151+ thrown .printStackTrace (pw );
152+ pw .close ();
153+ builder .append (sw .toString ());
154+ }
155+ return builder .toString ();
156+ }
157+
158+ public static boolean levelMatches (Level msgLevel , Level desiredLevel ) {
159+ return msgLevel .intValue () >= desiredLevel .intValue ();
160+ }
96161
97162 static {
98163 levelRange = new DSList ();
0 commit comments