You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LogFileLocator.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. * Copyright (c) 2006-2015 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.logging;
  23. import com.dmdirc.ClientModule.GlobalConfig;
  24. import com.dmdirc.DMDircMBassador;
  25. import com.dmdirc.commandline.CommandLineOptionsModule.Directory;
  26. import com.dmdirc.config.ConfigBinding;
  27. import com.dmdirc.events.UserErrorEvent;
  28. import com.dmdirc.interfaces.Connection;
  29. import com.dmdirc.interfaces.GroupChat;
  30. import com.dmdirc.interfaces.User;
  31. import com.dmdirc.interfaces.config.AggregateConfigProvider;
  32. import com.dmdirc.logger.ErrorLevel;
  33. import com.dmdirc.plugins.PluginDomain;
  34. import java.io.File;
  35. import java.math.BigInteger;
  36. import java.security.MessageDigest;
  37. import java.security.NoSuchAlgorithmException;
  38. import java.text.SimpleDateFormat;
  39. import java.util.Date;
  40. import java.util.Optional;
  41. import javax.annotation.Nullable;
  42. import javax.inject.Inject;
  43. import javax.inject.Provider;
  44. import javax.inject.Singleton;
  45. /**
  46. * Facilitates finding a path for log files.
  47. */
  48. @Singleton
  49. public class LogFileLocator {
  50. private final DMDircMBassador eventBus;
  51. private final Provider<String> directoryProvider;
  52. /** Whether to append a hash of the file name to the file name... */
  53. @ConfigBinding(key = "advanced.filenamehash")
  54. private boolean filenamehash;
  55. /** Whether to create a new folder for each network. */
  56. @ConfigBinding(key = "general.networkfolders")
  57. private boolean networkfolders;
  58. /** Whether to use date formats in file names. */
  59. @ConfigBinding(key = "advanced.usedate")
  60. private boolean usedate;
  61. /** Date format to use in file names if {@link #usedate} is true. */
  62. @ConfigBinding(key = "advanced.usedateformat")
  63. private String usedateformat;
  64. @Inject
  65. public LogFileLocator(
  66. final DMDircMBassador eventBus,
  67. @Directory(LoggingModule.LOGS_DIRECTORY) final Provider<String> directoryProvider,
  68. @GlobalConfig final AggregateConfigProvider globalConfig,
  69. @PluginDomain(LoggingPlugin.class) final String domain) {
  70. this.eventBus = eventBus;
  71. this.directoryProvider = directoryProvider;
  72. globalConfig.getBinder().withDefaultDomain(domain).bind(this, LogFileLocator.class);
  73. }
  74. /**
  75. * Sanitises the log file directory.
  76. *
  77. * @return Log directory
  78. */
  79. private StringBuffer getLogDirectory() {
  80. final StringBuffer directory = new StringBuffer();
  81. directory.append(directoryProvider.get());
  82. if (directory.charAt(directory.length() - 1) != File.separatorChar) {
  83. directory.append(File.separatorChar);
  84. }
  85. return directory;
  86. }
  87. /**
  88. * Get the name of the log file for a specific object.
  89. *
  90. * @param channel Channel to get the name for
  91. *
  92. * @return the name of the log file to use for this object.
  93. */
  94. public String getLogFile(final GroupChat channel) {
  95. final StringBuffer directory = getLogDirectory();
  96. final StringBuffer file = new StringBuffer();
  97. final Optional<String> network = channel.getConnection().map(Connection::getNetwork);
  98. network.ifPresent(n -> addNetworkDir(directory, file, n));
  99. file.append(sanitise(channel.getName().toLowerCase()));
  100. return getPath(directory, file, channel.getName());
  101. }
  102. /**
  103. * Get the name of the log file for a specific object.
  104. *
  105. * @param user Client to get the name for
  106. *
  107. * @return the name of the log file to use for this object.
  108. */
  109. public String getLogFile(final User user) {
  110. final StringBuffer directory = getLogDirectory();
  111. final StringBuffer file = new StringBuffer();
  112. addNetworkDir(directory, file, user.getConnection().getNetwork());
  113. file.append(sanitise(user.getNickname().toLowerCase()));
  114. return getPath(directory, file, user.getNickname());
  115. }
  116. /**
  117. * Get the name of the log file for a specific object.
  118. *
  119. * @param descriptor Description of the object to get a log file for.
  120. *
  121. * @return the name of the log file to use for this object.
  122. */
  123. public String getLogFile(@Nullable final String descriptor) {
  124. final StringBuffer directory = getLogDirectory();
  125. final StringBuffer file = new StringBuffer();
  126. final String md5String;
  127. if (descriptor == null) {
  128. file.append("null.log");
  129. md5String = "";
  130. } else {
  131. file.append(sanitise(descriptor.toLowerCase()));
  132. md5String = descriptor;
  133. }
  134. return getPath(directory, file, md5String);
  135. }
  136. /**
  137. * Gets the path for the given file and directory. Only intended to be used from getLogFile
  138. * methods.
  139. *
  140. * @param directory Log file directory
  141. * @param file Log file path
  142. * @param md5String Log file object MD5 hash
  143. *
  144. * @return Name of the log file
  145. */
  146. public String getPath(final StringBuffer directory, final StringBuffer file,
  147. final String md5String) {
  148. if (usedate) {
  149. final String dateFormat = usedateformat;
  150. final String dateDir = new SimpleDateFormat(dateFormat).format(new Date());
  151. directory.append(dateDir);
  152. if (directory.charAt(directory.length() - 1) != File.separatorChar) {
  153. directory.append(File.separatorChar);
  154. }
  155. if (!new File(directory.toString()).exists()
  156. && !new File(directory.toString()).mkdirs()) {
  157. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.LOW, null,
  158. "Unable to create date dirs", ""));
  159. }
  160. }
  161. if (filenamehash) {
  162. file.append('.');
  163. file.append(md5(md5String));
  164. }
  165. file.append(".log");
  166. return directory + file.toString();
  167. }
  168. /**
  169. * This function adds the networkName to the log file. It first tries to create a directory for
  170. * each network, if that fails it will prepend the networkName to the filename instead.
  171. *
  172. * @param directory Current directory name
  173. * @param file Current file name
  174. * @param networkName Name of network
  175. */
  176. protected void addNetworkDir(final StringBuffer directory, final StringBuffer file,
  177. final String networkName) {
  178. if (!networkfolders) {
  179. return;
  180. }
  181. final String network = sanitise(networkName.toLowerCase());
  182. boolean prependNetwork = false;
  183. // Check dir exists
  184. final File dir = new File(directory + network + System.getProperty(
  185. "file.separator"));
  186. if (dir.exists() && !dir.isDirectory()) {
  187. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.LOW, null,
  188. "Unable to create networkfolders dir (file exists instead)", ""));
  189. // Prepend network name to file instead.
  190. prependNetwork = true;
  191. } else if (!dir.exists() && !dir.mkdirs()) {
  192. eventBus.publishAsync(new UserErrorEvent(ErrorLevel.LOW, null,
  193. "Unable to create networkfolders dir", ""));
  194. prependNetwork = true;
  195. }
  196. if (prependNetwork) {
  197. file.insert(0, " -- ");
  198. file.insert(0, network);
  199. } else {
  200. directory.append(network);
  201. directory.append(System.getProperty("file.separator"));
  202. }
  203. }
  204. /**
  205. * Sanitise a string to be used as a filename.
  206. *
  207. * @param name String to sanitise
  208. *
  209. * @return Sanitised version of name that can be used as a filename.
  210. */
  211. protected static String sanitise(final String name) {
  212. // Replace illegal chars with
  213. return name.replaceAll("[^\\w\\.\\s\\-#&_]", "_");
  214. }
  215. /**
  216. * Get the md5 hash of a string.
  217. *
  218. * @param string String to hash
  219. *
  220. * @return md5 hash of given string
  221. */
  222. protected static String md5(final String string) {
  223. try {
  224. final MessageDigest m = MessageDigest.getInstance("MD5");
  225. m.update(string.getBytes(), 0, string.length());
  226. return new BigInteger(1, m.digest()).toString(16);
  227. } catch (NoSuchAlgorithmException e) {
  228. return "";
  229. }
  230. }
  231. }