View Javadoc
1   /*
2    * Copyright (c) 2002-2019, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34   	
35  package fr.paris.lutece.plugins.managelogs.web;
36  
37  import fr.paris.lutece.plugins.managelogs.util.ManageLogsUtil;
38  import fr.paris.lutece.portal.service.util.AppLogService;
39  import fr.paris.lutece.portal.service.util.AppPropertiesService;
40  import fr.paris.lutece.portal.util.mvc.admin.annotations.Controller;
41  import fr.paris.lutece.portal.util.mvc.commons.annotations.Action;
42  import fr.paris.lutece.portal.util.mvc.commons.annotations.View;
43  import fr.paris.lutece.util.ReferenceList;
44  
45  import javax.servlet.http.HttpServletRequest;
46  import java.io.IOException;
47  import java.nio.charset.Charset;
48  import java.nio.file.DirectoryStream;
49  import java.nio.file.Files;
50  import java.nio.file.Path;
51  import java.nio.file.Paths;
52  import java.util.*;
53  
54  import static fr.paris.lutece.plugins.managelogs.web.AbstractManageLogsPropertiesJspBean.RIGHT_MANAGELOGSPROPERTIES;
55  
56  /**
57   * This class provides the user interface to download logs
58   */
59  @Controller( controllerJsp = "DownloadLog.jsp", controllerPath = "jsp/admin/plugins/managelogs/", right = RIGHT_MANAGELOGSPROPERTIES )
60  public class DownloadLogJspBean extends AbstractManageLogsPropertiesJspBean
61  {
62      static final long serialVersionUID = -1;
63      
64      // Templates
65      private static final String TEMPLATE_MANAGE_LOGPROPERTIESS = "/admin/plugins/managelogs/download_logs.html";
66  
67      // Parameters
68      private static final String PARAMETER_ID_LOG = "idLog";
69  
70      // Properties for page titles
71      private static final String PROPERTY_PAGE_TITLE_MANAGE_LOGPROPERTIESS = "managelogs.manage_logdownload.pageTitle";
72  
73      // Markers
74      private static final String MARK_LIST_LOGS = "logs_list";
75      // Properties
76  
77      // Validations
78  
79      // Views
80      private static final String VIEW_DEFAULT = "listLogs";
81  
82      // Actions
83      private static final String ACTION_DOWNLOAD_LOG = "download";
84  
85      // Infos
86  
87      // Errors
88  
89  
90      // Session variable to store working values
91  
92      private static final String CONTENT_TYPE = "application/octet-stream";
93  
94  
95      /**
96       * Build the Manage View
97       * @param request The HTTP request
98       * @return The page
99       */
100     @View( value = VIEW_DEFAULT, defaultView = true )
101     public String getLogs( HttpServletRequest request )
102     {
103         Map<String, Object> model = new HashMap<>(  );
104 
105         ReferenceList rf = getLogFilesReferenceList();
106 
107         if ( rf.isEmpty() )
108         {
109             // no conf found or no log file
110             AppLogService.error( "No log file found" );
111         }
112 
113         model.put( MARK_LIST_LOGS, rf );
114 
115         return getPage( PROPERTY_PAGE_TITLE_MANAGE_LOGPROPERTIESS, TEMPLATE_MANAGE_LOGPROPERTIESS, model );
116     }
117 
118     private static ReferenceList getLogFilesReferenceList()
119     {
120         ReferenceList rf = new ReferenceList();
121 
122         Set<String> setLogFiles = getLogFiles();
123 
124         if ( setLogFiles.isEmpty() )
125         {
126             // no conf found or no log file
127             AppLogService.error( "No log file found" );
128         }
129         else
130         {
131             // sort files
132             List<String> listFilesSorted = new ArrayList<>( setLogFiles );
133             Collections.sort( listFilesSorted );
134 
135             int i=0;
136             for ( String file : listFilesSorted )
137             {
138                 rf.addItem( i, file );
139                 i++;
140             }
141         }
142 
143         return rf;
144     }
145 
146     /**
147      * find log configurations and get log files from them
148      * @return list of log file names (with path)
149      */
150     private static Set<String> getLogFiles()
151     {
152         // Using set to avoid duplicates
153         Set<String> setLogs = new HashSet<>( );
154 
155         // STEP 1: get all configuration and log files
156         String log4jConfigFile = null;
157 
158         // get log file from log4j configuration
159         if ( !APP_SERVER_MULTI_WEBAPP )
160         {
161             log4jConfigFile = System.getProperty( "log4j.configuration" );
162             if ( ManageLogsUtil.isFileReadable( log4jConfigFile ) )
163             {
164                 setLogs.addAll( readLogConf( log4jConfigFile ) );
165             }
166         }
167 
168         // try to find tmp log conf
169         setLogs.addAll( getLogsFromFile( TMP_LOG_ABSOLUTE, log4jConfigFile ) );
170 
171         // try to find log.properties
172         setLogs.addAll( getLogsFromFile( ALTERNATE_LOG_CONF_FILE_ABSOLUTE, log4jConfigFile ) );
173 
174         // try to find config.properties
175         setLogs.addAll( getLogsFromFile( LUTECE_CONF_FILE_ABSOLUTE, log4jConfigFile ) );
176 
177         // additionnal logs defined in managelogs.properties
178         String strListAdditionalLogDir = AppPropertiesService.getProperty( "managelogs.addlog.folder" );
179         if ( strListAdditionalLogDir != null )
180         {
181             for ( String logDir : strListAdditionalLogDir.split( ";" ) )
182             {
183                 if ( !ManageLogsUtil.isNullOrEmptyWithTrim( logDir ) )
184                 {
185                     try
186                     {
187                         setLogs.addAll ( listFilesInDirectory( logDir.trim() ) );
188                     }
189                     catch ( IOException e )
190                     {
191                         AppLogService.error( "Error getting additionnal files from " + logDir, e );
192                     }
193                 }
194             }
195         }
196 
197         return setLogs;
198     }
199 
200     private static Set<String> getLogsFromFile( String file, String log4jConfigFile )
201     {
202         Set<String> setLogs = new HashSet<>( );
203         if ( !file.equalsIgnoreCase( log4jConfigFile ) && ManageLogsUtil.isFileReadable( file ) )
204         {
205             setLogs.addAll( readLogConf( file ) );
206         }
207         return setLogs;
208     }
209 
210     /**
211      * read config file and log files from them
212      * @param fileName log configuration file
213      * @return list of log file names (with path)
214      */
215     private static Set<String> readLogConf( String fileName )
216     {
217         Set<String> logFile = new HashSet<>(  );
218         try
219         {
220             List<String> lines = Files.readAllLines( Paths.get( fileName ), Charset.defaultCharset( ) );
221 
222             List<String> listFilesFromConfiguration = getFilesFromConfiguration( lines, false );
223 
224             for ( String fileFromConfiguration : listFilesFromConfiguration )
225             {
226                 String absoluteDirectory = Paths.get( fileFromConfiguration ).getParent().toString();
227 
228                 // listing all files
229                 Set<String> filesInDirectory = listFilesInDirectory( absoluteDirectory );
230                 for ( String strFileInDirectory : filesInDirectory )
231                 {
232                     // check if the listed file is a derivative of the configured log file (log rotation)
233                     if ( Paths.get( strFileInDirectory ).getFileName().toString().startsWith( Paths.get( fileFromConfiguration ).getFileName().toString() ) )
234                     {
235                         logFile.add( Paths.get( strFileInDirectory ).toString() );
236                     }
237                 }
238             }
239         }
240         catch ( IOException e )
241         {
242             AppLogService.error( "Error reading file " + fileName, e );
243         }
244 
245         return logFile;
246     }
247 
248 
249 
250     /**
251      * Return files of a directory, with check of allowed directories
252      * @param dir directory to list
253      * @return list of files in directory
254      * @throws IOException error in reading the directory
255      */
256     private static Set<String> listFilesInDirectory( String dir ) throws IOException
257     {
258         Set<String> fileList = new HashSet<>();
259         if ( ManageLogsUtil.isFileReadable( dir ) )
260         {
261             try ( DirectoryStream<Path> stream = Files.newDirectoryStream( Paths.get( dir ) ) )
262             {
263                 for ( Path path : stream )
264                 {
265                     if ( !Files.isDirectory( path ) && isLogFileAccessible( path.toString( ) ) )
266                     {
267                         fileList.add( path.toString( ) );
268                     }
269                 }
270             }
271         }
272         return fileList;
273     }
274 
275     /**
276      * Download a file
277      *
278      * @param request
279      *            The HTTP request
280      * @return The page
281      */
282     @Action( ACTION_DOWNLOAD_LOG )
283     public String exportCategories( HttpServletRequest request )
284     {
285         String strId =request.getParameter( PARAMETER_ID_LOG );
286 
287         // get logs list
288         ReferenceList listRF = DownloadLogJspBean.getLogFilesReferenceList();
289 
290         if ( strId == null || Integer.parseInt( strId ) > listRF.size() )
291         {
292             AppLogService.error( "Error, log number null or invalid" );
293         }
294         else
295         {
296 
297             Path path = Paths.get( listRF.get( Integer.parseInt( strId ) ).getName() );
298 
299             try
300             {
301                 download( Files.readAllBytes( path ), path.getFileName().toString(), CONTENT_TYPE );
302             }
303             catch ( IOException e )
304             {
305                 AppLogService.error( "Error downloading file", e );
306             }
307         }
308 
309         return getLogs( request );
310     }
311 
312 }