1+ /*
2+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+ * The Universal Permissive License (UPL), Version 1.0
4+ */
5+ package oracle .weblogic .deploy .logging ;
6+
7+ import java .util .ArrayList ;
8+ import java .util .List ;
9+ import java .util .Properties ;
10+ import java .util .logging .ConsoleHandler ;
11+ import java .util .logging .Formatter ;
12+ import java .util .logging .Handler ;
13+ import java .util .logging .Level ;
14+ import java .util .logging .LogManager ;
15+ import java .util .logging .LogRecord ;
16+ import java .util .logging .MemoryHandler ;
17+
18+ import oracle .weblogic .deploy .util .WLSDeployContext ;
19+ import oracle .weblogic .deploy .util .WLSDeployExit ;
20+
21+
22+ /**
23+ * This class save the log records logged by the tool at Info level or greater. The WLSDeployExit exit method will
24+ * call this Handler to publish the messages, along with the total of the log records, by Level category.
25+ *
26+ * The WLSDeployCustomizeLoggingConfig adds the properties from this class' getHandlerProperties() to the
27+ * log manager logger properties and adds the handler to the root WLSDEPLOY Logger. See the class for information
28+ * on how to inject this handler into the wlsdeploy root logger.
29+ *
30+ * Before the tool exit, if specified by the caller, an activity summary of the saved logs is displayed to the console.
31+ * A final total of the records logged by the tool for the Level categories indicated above is displayed to the console.
32+ *
33+ * @see WLSDeployCustomizeLoggingConfig
34+ * @see oracle.weblogic.deploy.util.WLSDeployExit
35+ */
36+ public class SummaryHandler extends Handler implements WLSDeployLogEndHandler {
37+ private static final String CLASS = SummaryHandler .class .getName ();
38+ private static final String LEVEL_PROPERTY = "level" ;
39+ private static final String TARGET_PROPERTY = "target" ;
40+ private static final String FORMATTER_PROPERTY = "formatter" ;
41+ private static final String SIZE_PROPERTY = "size" ;
42+ private static final int DEFAULT_SIZE = 3000 ;
43+
44+ private PlatformLogger LOGGER = WLSDeployLogFactory .getLogger ("wlsdeploy.exit" );
45+ private int bufferSize ;
46+ private WLSDeployContext context ;
47+
48+ private Handler topTarget ;
49+ private List <LevelHandler > handlers = new ArrayList <>();
50+ private boolean closed = false ;
51+
52+ /**
53+ * This default constructor is populated with the handler properties loaded by the WLSDeployCustomizeLoggingConfig.
54+ */
55+ public SummaryHandler () {
56+ super ();
57+ configure ();
58+
59+ LOGGER .setLevel (Level .INFO );
60+ addLevelHandler (Level .WARNING );
61+ addLevelHandler (Level .SEVERE );
62+ }
63+
64+ /**
65+ * Tally and save the log record if it matches one of the category Level handlers. Once the summary has completed,
66+ * all further log records will be ignored.
67+ *
68+ * @param record to tally and save in handler with matching Level category
69+ */
70+ @ Override
71+ public synchronized void publish (LogRecord record ) {
72+ // after close, take yourself out of the mix. The stored up log messages are going to go to the
73+ // console handler anyway
74+ if (!closed ) {
75+ for (Handler handler : handlers ) {
76+ handler .publish (record );
77+ }
78+ }
79+ }
80+
81+ @ Override
82+ public void flush () {
83+ topTarget .flush ();
84+ }
85+
86+ @ Override
87+ public void close () throws SecurityException {
88+ topTarget .close ();
89+ }
90+
91+ /**
92+ * This method is called by the tool to complete the SummaryHandler, and display the recap and total information
93+ * to the console. The log records are only displayed to the console if the tool was run in online mode.
94+ * This compensates for wlst writing spurious blank lines to the console during online mode.
95+ *
96+ * @param modelContext contextual information about the tool
97+ */
98+ @ Override
99+ public synchronized void logEnd (WLSDeployContext modelContext ) {
100+ closed = true ;
101+ String METHOD = "push" ;
102+ LOGGER .entering (modelContext , CLASS , METHOD );
103+ this .context = modelContext ;
104+ summaryHead (topTarget );
105+ for (LevelHandler handler : handlers ) {
106+ handler .push ();
107+ }
108+ summaryTail (topTarget );
109+ LOGGER .exiting (CLASS , METHOD );
110+ }
111+
112+ /**
113+ * The WLSDeployLoggingConfig will call this method to add to the logging.properties files.
114+ * If the logging.properties already contains the property, the property in this list will be ignored.
115+ *
116+ * @return properties to set in logging.properties
117+ */
118+ public static Properties getHandlerProperties () {
119+ Properties properties = new Properties ();
120+ properties .setProperty (LEVEL_PROPERTY , Level .INFO .getName ());
121+ properties .setProperty (TARGET_PROPERTY , WLSDeployLoggingConsoleHandler .class .getName ());
122+ properties .setProperty (FORMATTER_PROPERTY , WLSDeployLogFormatter .class .getName ());
123+ return properties ;
124+ }
125+
126+ private void addLevelHandler (Level level ) {
127+ LevelHandler handler ;
128+ Handler levelTarget = getConsoleHandler ();
129+ levelTarget .setFormatter (new SummaryFormatter (level ));
130+ handler = new LevelHandler (levelTarget , bufferSize , level );
131+ handler .setLevel (level );
132+ handler .setFilter (getFilter ());
133+ handlers .add (handler );
134+ }
135+
136+ void summaryHead (Handler handler ) {
137+ handler .publish (getLogRecord ("WLSDPLY-21003" , context .getProgramName (),
138+ context .getVersion (), context .getWlstMode ()));
139+ }
140+
141+ void summaryTail (Handler handler ) {
142+ StringBuffer buffer = new StringBuffer ();
143+ java .util .Formatter fmt = new java .util .Formatter (buffer );
144+ for (LevelHandler levelHandler : handlers ) {
145+ if (levelHandler .getTotalRecords () >= 0 ) {
146+ fmt .format (" %1$s : %2$,5d" , levelHandler .getLevel ().getName (), levelHandler .getTotalRecords ());
147+ }
148+ }
149+ handler .publish (getLogRecord ("WLSDPLY-21002" , buffer ));
150+ }
151+
152+ private class TotalFormatter extends Formatter {
153+
154+ @ Override
155+ public synchronized String format (LogRecord record ) {
156+ return System .lineSeparator () + formatMessage (record ) + System .lineSeparator ();
157+ }
158+
159+ }
160+
161+ private class SummaryFormatter extends Formatter {
162+
163+ private final String MSG_FORMAT = " %1$5d. %2$s: %3$s" + System .lineSeparator ();
164+ private final String INTERNAL = System .lineSeparator () + "%s" + System .lineSeparator () + System .lineSeparator ();
165+ private int sequence = 0 ;
166+ private Level level ;
167+
168+ public SummaryFormatter (Level level ) {
169+ this .level = level ;
170+ }
171+
172+ @ Override
173+ public synchronized String format (LogRecord record ) {
174+ String message = "" ;
175+ String msgId = record .getMessage ();
176+ if (msgId .indexOf ('{' ) >= 0 ) {
177+ msgId = null ;
178+ }
179+ String formatted = formatMessage (record );
180+ if (msgId != null && !msgId .equals (formatted )) {
181+ // this has a msg id. don't post any that don't have msg id.
182+ message = String .format (MSG_FORMAT , ++sequence , msgId , formatted );
183+ }
184+ return message ;
185+ }
186+
187+ @ Override
188+ public String getHead (Handler handler ) {
189+ return String .format (INTERNAL , formatMessage (getLogRecord ("WLSDPLY-21000" , level .getLocalizedName ())));
190+ }
191+ }
192+
193+ private class LevelHandler extends MemoryHandler {
194+
195+ private int totalRecords ;
196+
197+ LevelHandler (Handler handler , int size , Level level ) {
198+ super (handler , size , Level .OFF );
199+ setLevel (level );
200+ }
201+
202+ @ Override
203+ public synchronized void publish (LogRecord record ) {
204+ if (record .getLevel ().intValue () == getLevel ().intValue ()) {
205+ ++totalRecords ;
206+ super .publish (record );
207+ }
208+ }
209+
210+ int getTotalRecords () {
211+ return totalRecords ;
212+ }
213+
214+ }
215+
216+ private void configure () {
217+ LogManager manager = LogManager .getLogManager ();
218+ topTarget = getConsoleHandler ();
219+ topTarget .setFormatter (new TotalFormatter ());
220+ bufferSize = getSize (manager .getProperty (getClass ().getName () + "." + SIZE_PROPERTY ));
221+ }
222+
223+ private int getSize (String propSize ) {
224+ Integer handlerSize ;
225+ try {
226+ handlerSize = new Integer (propSize );
227+ } catch (NumberFormatException nfe ) {
228+ handlerSize = DEFAULT_SIZE ;
229+ }
230+ return handlerSize ;
231+ }
232+
233+ private ConsoleHandler getConsoleHandler () {
234+ ConsoleHandler handler = null ;
235+ try {
236+ handler = (ConsoleHandler ) Class .forName (WLSDeployLoggingConfig .getConsoleHandler ()).newInstance ();
237+ } catch (ClassNotFoundException | IllegalAccessException cne ) {
238+ System .out .println ("Class not found " + WLSDeployLoggingConfig .getConsoleHandler ());
239+ } catch (InstantiationException ie ) {
240+ handler = new ConsoleHandler ();
241+ }
242+ return handler ;
243+ }
244+
245+
246+ private LogRecord getLogRecord (String msg , Object ... params ) {
247+ LogRecord record = new LogRecord (Level .INFO , msg );
248+ record .setLoggerName (LOGGER .getName ());
249+ if (params != null && params .length != 0 ) {
250+ record .setParameters (params );
251+ }
252+ record .setSourceClassName (CLASS );
253+ record .setSourceMethodName ("" );
254+ record .setResourceBundle (LOGGER .getUnderlyingLogger ().getResourceBundle ());
255+ return record ;
256+ }
257+
258+ }
0 commit comments