View Javadoc

1   package net.sf.appstatus.core.services;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.Set;
6   
7   import org.apache.commons.lang3.StringUtils;
8   import org.apache.commons.lang3.text.StrSubstitutor;
9   import org.slf4j.Logger;
10  import org.slf4j.LoggerFactory;
11  
12  /**
13   * Default support implementation, with logging.
14   * 
15   * @author Nicolas Richeton
16   * 
17   */
18  public abstract class AbstractLoggingServiceMonitor extends AbstractServiceMonitor {
19  	private static Logger stdLogger = LoggerFactory.getLogger(AbstractLoggingServiceMonitor.class);
20  
21  	protected boolean cacheHit = false;
22  	protected Map<String, String> context = null;
23  	protected String correlationId = null;
24  	private final boolean enableLog;
25  	protected Long endTime = null;
26  	protected boolean error = false;
27  	protected String errorMessage = null;
28  	protected Long executionTime = null;
29  	protected boolean failure = false;
30  	protected Exception failureException = null;
31  	protected String failureReason = null;
32  	private Logger logger = null;
33  	private String messageFormat = "${correlationId}|${group}|${name}|${responseTime}|${cache}|${status}|${statusMessage}";
34  	protected Object[] parameters;
35  	private final IService service;
36  	protected long startTime;
37  
38  	public AbstractLoggingServiceMonitor(IService service, boolean enableLog, boolean useThreadLocal) {
39  		super(useThreadLocal);
40  		this.service = service;
41  		this.enableLog = enableLog;
42  		startTime = System.currentTimeMillis();
43  	}
44  
45  	@Override
46  	public void beginCall(Object... parameters) {
47  		super.beginCall(parameters);
48  		this.parameters = parameters;
49  	}
50  
51  	public void cacheHit() {
52  		if (!this.cacheHit) {
53  			cacheHit = true;
54  		}
55  	}
56  
57  	public void context(String name, String value) {
58  		if (context == null) {
59  			context = new HashMap<String, String>();
60  		}
61  
62  		context.put(name, value);
63  
64  	}
65  
66  	public void correlationId(String correlationId) {
67  		this.correlationId = correlationId;
68  	}
69  
70  	@Override
71  	public void endCall() {
72  		if (endTime != null) {
73  			// endCall was called twice ! returning directly.
74  			return;
75  		}
76  
77  		super.endCall();
78  
79  		endTime = System.currentTimeMillis();
80  
81  		if (executionTime == null) {
82  			executionTime = endTime - startTime;
83  		}
84  
85  		if (enableLog) {
86  			Logger log = getLogger();
87  			if (log.isInfoEnabled()) {
88  				log.info(getLogMessage());
89  
90  			}
91  		}
92  	}
93  
94  	public void error(String message) {
95  		error = true;
96  		errorMessage = message;
97  	}
98  
99  	public void executionTime(long timeMillis) {
100 		executionTime = timeMillis;
101 
102 	}
103 
104 	public void failure(String reason) {
105 		failure(reason, null);
106 	}
107 
108 	public void failure(String reason, Exception e) {
109 		this.failure = true;
110 		this.failureReason = reason;
111 		this.failureException = e;
112 	}
113 
114 	protected Logger getLogger() {
115 		if (logger != null) {
116 			return logger;
117 		}
118 
119 		return stdLogger;
120 	}
121 
122 	/**
123 	 * Returns the log message (at the end of the call).
124 	 * <p>
125 	 * This method can be overridden for very complex messages.
126 	 * 
127 	 * @return
128 	 */
129 	protected String getLogMessage() {
130 
131 		Map<String, String> valuesMap = new HashMap<String, String>();
132 		valuesMap.put("responseTime", String.valueOf(executionTime));
133 		valuesMap.put("group", service.getGroup());
134 		valuesMap.put("name", service.getName());
135 		valuesMap.put("cache", cacheHit ? "HIT" : "MISS");
136 		valuesMap.put("failure", failure ? "FAILURE" : StringUtils.EMPTY);
137 		valuesMap.put("failureReason", StringUtils.defaultString(failureReason));
138 		valuesMap.put("failureException", failureException != null ? failureException.getLocalizedMessage() : "");
139 		valuesMap.put("error", error ? "ERROR" : StringUtils.EMPTY);
140 		valuesMap.put("errorMessage", StringUtils.defaultString(errorMessage));
141 		valuesMap.put("correlationId", StringUtils.defaultString(correlationId));
142 
143 		// Populate context
144 		if (context != null) {
145 			Set<String> keys = context.keySet();
146 			for (String key : keys) {
147 				valuesMap.put(key, context.get(key));
148 			}
149 		}
150 
151 		// Populate status
152 		String status = "SUCCESS";
153 		String statusMessage = StringUtils.EMPTY;
154 		if (error) {
155 			status = "ERROR";
156 			statusMessage = errorMessage;
157 		}
158 		if (failure) {
159 			status = "FAILURE";
160 			statusMessage = failureReason;
161 		}
162 		valuesMap.put("status", status);
163 		valuesMap.put("statusMessage", statusMessage);
164 
165 		StrSubstitutor sub = new StrSubstitutor(valuesMap);
166 
167 		return sub.replace(messageFormat);
168 	}
169 
170 	public long getStartTime() {
171 		return startTime;
172 	}
173 
174 	public void setLogFormat(String messageFormat) {
175 		this.messageFormat = messageFormat;
176 	}
177 
178 	public void setLogger(Logger l) {
179 		logger = l;
180 	}
181 
182 	/**
183 	 * Set the log message format, based on :
184 	 * http://commons.apache.org/lang/api-release/org/apache/commons/lang3/text/
185 	 * StrSubstitutor.html
186 	 * 
187 	 * <p>
188 	 * Example :
189 	 * <code>${correlationId}|${group}|${name}|${responseTime}|${cache}|${status}|${statusMessage}</code>
190 	 * </p>
191 	 * 
192 	 * <p>
193 	 * Available variables :
194 	 * </p>
195 	 * 
196 	 * <ul>
197 	 * <li>group</li>
198 	 * <li>name</li>
199 	 * <li>responseTime</li>
200 	 * <li>cache</li>
201 	 * <li>failure</li>
202 	 * <li>failureReason</li>
203 	 * <li>failureException</li>
204 	 * <li>error</li>
205 	 * <li>errorMessage</li>
206 	 * <li>correlationId</li>
207 	 * <li>status : SUCCESS/FAILURE/ERROR</li>
208 	 * <li>statusMessage : failure or error message</li>
209 	 * <li>Any additional context values</li>
210 	 * </ul>
211 	 * 
212 	 * @param messageFormat
213 	 * @deprecated Use {@link #setLogFormat(String)} instead
214 	 */
215 	@Deprecated
216 	public void setMessageFormat(String messageFormat) {
217 		setLogFormat(messageFormat);
218 	}
219 }