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 8.9KB

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