Newer
Older
snipet / KTool / trunk / src / jp / ehobby / logging / SyslogHandler.java
  1. package jp.ehobby.logging;
  2.  
  3. import java.io.IOException;
  4. import java.net.SocketException;
  5. import java.net.UnknownHostException;
  6. import java.util.HashMap;
  7. import java.util.logging.Formatter;
  8. import java.util.logging.Handler;
  9. import java.util.logging.Level;
  10. import java.util.logging.LogManager;
  11. import java.util.logging.LogRecord;
  12.  
  13. import jp.ehobby.info.SystemInfo;
  14. import jp.ehobby.util.number.NumberUtilities;
  15. import jp.ehobby.util.syslog.Syslog;
  16. import jp.ehobby.util.syslog.SyslogFacility;
  17. import jp.ehobby.util.syslog.SyslogSeverity;
  18.  
  19.  
  20. /**
  21. * Syslog に書き出す Handler.
  22. * SyslogHandler として以下の設定が可能です.
  23. * <pre>
  24. * jp.ehobby.logging.SyslogHandler.server = Syslogサーバのアドレス (デフォルト:localhost)
  25. * jp.ehobby.logging.SyslogHandler.port = Syslogサーバのポート (デフォルト:514)
  26. * jp.ehobby.logging.SyslogHandler.tag = Syslogのタグ (デフォルト:指定なし)
  27. * jp.ehobby.logging.SyslogHandler.facility = Syslog分類 (デフォルト:USER_LEVEL)
  28. * jp.ehobby.logging.SyslogHandler.FINEST = Syslog重要度 (デフォルト:DEBUG)
  29. * jp.ehobby.logging.SyslogHandler.FINER = Syslog重要度 (デフォルト:DEBUG)
  30. * jp.ehobby.logging.SyslogHandler.FINE = Syslog重要度 (デフォルト:DEBUG)
  31. * jp.ehobby.logging.SyslogHandler.CONFIG = Syslog重要度 (デフォルト:INFORMATIONAL)
  32. * jp.ehobby.logging.SyslogHandler.INFO = Syslog重要度 (デフォルト:INFORMATIONAL)
  33. * jp.ehobby.logging.SyslogHandler.WARNING = Syslog重要度 (デフォルト:WARNING)
  34. * jp.ehobby.logging.SyslogHandler.SEVERE = Syslog重要度 (デフォルト:CRITICAL)
  35. *
  36. * Syslogのタグのキーが存在しない場合、タグが出力されません.
  37. * Syslogのタグのキーが存在する場合、「[PID]」がログに書き出されます.
  38. * Syslogのタグが指定されている場合、「指定されたタグ[PID]」がログに書き出されます.
  39. * Syslog分類には {@link jp.ehobby.util.syslog.SyslogFacility} の定数名を指定可能です.
  40. * Syslog重要度には {@link jp.ehobby.util.syslog.SyslogSeverity} の定数名を指定可能です.
  41. * </pre>
  42. *
  43. * @author kei-n
  44. */
  45. public class SyslogHandler extends Handler {
  46.  
  47.  
  48. /** Level リスト. */
  49. private static final Level[] LEVEL_LIST = {
  50. Level.FINEST,
  51. Level.FINER,
  52. Level.FINE,
  53. Level.CONFIG,
  54. Level.INFO,
  55. Level.WARNING,
  56. Level.SEVERE
  57. };
  58.  
  59. /** デフォルトの Severity. */
  60. private static final SyslogSeverity[] DEFAULT_SEVERITYS = {
  61. SyslogSeverity.DEBUG,
  62. SyslogSeverity.DEBUG,
  63. SyslogSeverity.DEBUG,
  64. SyslogSeverity.INFORMATIONAL,
  65. SyslogSeverity.INFORMATIONAL,
  66. SyslogSeverity.WARNING,
  67. SyslogSeverity.CRITICAL
  68. };
  69.  
  70. /** Syslog 出力用. */
  71. private final Syslog syslog;
  72.  
  73. /** Syslog レベル. */
  74. private final HashMap<Level, SyslogSeverity> levelMap;
  75.  
  76. /** Syslog 分類. */
  77. private final SyslogFacility facility;
  78.  
  79. /** ローカルホスト名. */
  80. private final String hostName;
  81.  
  82. /** Tag名. */
  83. private final String tag;
  84.  
  85. /** syslog が close されたか否かを表す. */
  86. private boolean closed;
  87.  
  88.  
  89. /**
  90. * SyslogHandler を構築します.
  91. *
  92. * @throws SocketException Socketエラー
  93. * @throws UnknownHostException 不明なホスト
  94. */
  95. public SyslogHandler() throws SocketException, UnknownHostException {
  96. LogManager logMgr = LogManager.getLogManager();
  97. String cName = getClass().getName();
  98.  
  99. this.syslog = createSyslog(logMgr, cName);
  100. this.facility = createFacility(logMgr, cName);
  101. this.levelMap = createLevelMap(logMgr, cName);
  102. this.hostName = SystemInfo.getLocalHostName();
  103. this.tag = logMgr.getProperty(cName + ".tag"); //$NON-NLS-1$
  104. this.closed = false;
  105.  
  106. // その他設定
  107. configure(logMgr, cName);
  108. }
  109.  
  110.  
  111. @Override
  112. public void publish(final LogRecord record) {
  113. if (this.closed) { return; }
  114. if (!isLoggable(record)) { return; }
  115.  
  116. Level level = record.getLevel();
  117. SyslogSeverity severity = this.levelMap.get(level);
  118. Formatter fmt = getFormatter();
  119. String message = record.getMessage();
  120. if (fmt != null) {
  121. message = fmt.format(record);
  122. }
  123.  
  124. try {
  125. this.syslog.logger(
  126. this.facility,
  127. severity,
  128. this.hostName,
  129. this.tag,
  130. message);
  131. } catch (IOException e) {
  132. // Nothing to do.
  133. }
  134.  
  135. }
  136.  
  137.  
  138. @Override
  139. public void flush() {
  140. // Nothing to do.
  141. }
  142.  
  143.  
  144. @Override
  145. public synchronized void close() throws SecurityException {
  146. if (this.closed) { return; }
  147. this.closed = true;
  148. try {
  149. this.syslog.close();
  150. } catch (IOException e) {
  151. // NOP
  152. }
  153. }
  154.  
  155.  
  156. ////////////////////////////////////////////////////////////////////////////
  157. //
  158. // Syslog の設定
  159. //
  160.  
  161. /**
  162. * Syslogの設定を実施します.
  163. *
  164. * @param mgr LogManager
  165. * @param cName クラス名
  166. */
  167. private void configure(final LogManager mgr, final String cName) {
  168. Formatter newFormatter = createFormatter(mgr, cName);
  169. setFormatter(newFormatter);
  170. }
  171.  
  172.  
  173. /**
  174. * 設定ファイルに指定されたサーバ、ポートにログを書き込む Syslog を構築します.
  175. *
  176. * @param mgr LogManager
  177. * @param cName クラス名
  178. * @return Syslog
  179. * @throws SocketException ソケットエラー
  180. * @throws UnknownHostException 不明なホスト
  181. */
  182. private static Syslog createSyslog(final LogManager mgr, final String cName) throws SocketException, UnknownHostException {
  183. // Syslog サーバ
  184. String server = mgr.getProperty(cName + ".server"); //$NON-NLS-1$
  185. if (server == null) {
  186. server = "localhost"; //$NON-NLS-1$
  187. }
  188.  
  189. // Syslog サーバポート
  190. String portStr = mgr.getProperty(cName + ".port"); //$NON-NLS-1$
  191. int port = Syslog.SERVER_PORT;
  192. if (portStr != null) {
  193. port = (int) NumberUtilities.longValue(portStr);
  194. }
  195.  
  196. return new Syslog(server, port);
  197. }
  198.  
  199.  
  200. /**
  201. * Syslog に出力する分類を生成します.
  202. *
  203. * @param mgr LogManager
  204. * @param cName クラス名
  205. * @return SyslogFacility
  206. */
  207. private static SyslogFacility createFacility(final LogManager mgr, final String cName) {
  208. // Syslog 分類設定
  209. String facilityName = mgr.getProperty(cName + ".facility"); //$NON-NLS-1$
  210. if (facilityName == null) {
  211. facilityName = SyslogFacility.USER_LEVEL.name();
  212. }
  213. return SyslogFacility.valueOf(facilityName);
  214. }
  215.  
  216.  
  217. /**
  218. * LevelとSyslogの重要度対応MAPを生成します.
  219. *
  220. * @param mgr LogManager
  221. * @param cName クラス名
  222. * @return LevelとSyslogの重要度対応MAP
  223. */
  224. private static HashMap<Level, SyslogSeverity> createLevelMap(final LogManager mgr, final String cName) {
  225. HashMap<Level, SyslogSeverity> map = new HashMap<>();
  226.  
  227. for (int i = 0; i < LEVEL_LIST.length; i++) {
  228. String key = LEVEL_LIST[i].getName();
  229. String val = mgr.getProperty(cName + '.' + key);
  230. SyslogSeverity severity = DEFAULT_SEVERITYS[i];
  231. if (val != null) {
  232. try {
  233. severity = SyslogSeverity.valueOf(val);
  234. } catch (IllegalArgumentException e) {
  235. // NOP
  236. }
  237. }
  238. map.put(LEVEL_LIST[i], severity);
  239. }
  240. return map;
  241. }
  242.  
  243.  
  244. /**
  245. * Formatter を返します.
  246. * Formatter が指定されていない場合、そのままのメッセージを出力する Formatter を返します.
  247. *
  248. * @param mgr LogManager
  249. * @param cName クラス名
  250. * @return Formatter
  251. */
  252. private static Formatter createFormatter(final LogManager mgr, final String cName) {
  253. String val = mgr.getProperty(cName + ".formatter"); //$NON-NLS-1$
  254. if (val != null) {
  255. try {
  256. Class<Formatter> clz = (Class<Formatter>) ClassLoader.getSystemClassLoader().loadClass(val);
  257. return clz.newInstance();
  258. } catch (Exception e) {
  259. // Nothing to do.
  260. }
  261. }
  262. return new SyslogDefaultFormatter();
  263. }
  264.  
  265. }
  266.  
  267.  
  268. /**
  269. * SyslogのデフォルトFormatter.
  270. * 特にフォーマットを実施せず、そのままメッセージを出力する.
  271. */
  272. class SyslogDefaultFormatter extends Formatter {
  273.  
  274. @Override
  275. public String format(LogRecord record) {
  276. return record.getMessage();
  277. }
  278. }
  279.