    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.internal.services.exceptions;
    014
    015import org.apache.tapestry5.SymbolConstants;
    016import org.apache.tapestry5.ioc.annotations.Inject;
    017import org.apache.tapestry5.ioc.annotations.Symbol;
    018import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    019import org.apache.tapestry5.ioc.util.ExceptionUtils;
    020import org.apache.tapestry5.services.ExceptionReportWriter;
    021import org.apache.tapestry5.services.ExceptionReporter;
    022import org.slf4j.Logger;
    023
    024import java.io.File;
    025import java.io.IOException;
    026import java.io.PrintWriter;
    027import java.util.Date;
    028import java.util.concurrent.atomic.AtomicInteger;
    029
    030@SuppressWarnings("ResultOfMethodCallIgnored")
    031public class ExceptionReporterImpl implements ExceptionReporter
    032{
    033
    034    @Inject
    035    @Symbol(SymbolConstants.EXCEPTION_REPORTS_DIR)
    036    private File logDir;
    037
    038    @Inject
    039    @Symbol(SymbolConstants.RESTRICTIVE_ENVIRONMENT)
    040    private boolean restrictive;
    041
    042    private final AtomicInteger uid = new AtomicInteger();
    043
    044    @Inject
    045    private Logger logger;
    046
    047
    048    @Inject
    049    private ExceptionReportWriter exceptionReportWriter;
    050
    051    @Override
    052    public void reportException(Throwable exception)
    053    {
    054        Date date = new Date();
    055        String fileName = String.format(
    056                "exception-%tY%<tm%<td-%<tH%<tM%<tS-%<tL.%d.txt", date,
    057                uid.getAndIncrement());
    058
    059        File folder;
    060
    061        try
    062        {
    063            if (restrictive)
    064            {
    065                // Good luck with this; all exceptions written to a single folder.
    066                folder = logDir;
    067            } else
    068            {
    069                String folderName = String.format("%tY-%<tm-%<td/%<tH/%<tM", date);
    070                folder = new File(logDir, folderName);
    071
    072                folder.mkdirs();
    073            }
    074
    075            File log = new File(folder, fileName);
    076
    077            writeExceptionToFile(exception, log);
    078
    079            logger.warn(String.format("Wrote exception report to %s", toURI(log)));
    080        } catch (Exception ex)
    081        {
    082            logger.error(String.format("Unable to write exception report %s: %s",
    083                    fileName, ExceptionUtils.toMessage(ex)));
    084
    085            logger.error("Original exception:", exception);
    086        }
    087    }
    088
    089    private String toURI(File file)
    090    {
    091        try
    092        {
    093            return file.toURI().toString();
    094        } catch (Exception e)
    095        {
    096            return file.toString();
    097        }
    098    }
    099
    100    private void writeExceptionToFile(Throwable exception, File log) throws IOException
    101    {
    102        log.createNewFile();
    103
    104        PrintWriter writer = null;
    105
    106        try
    107        {
    108            writer = new PrintWriter(log);
    109            exceptionReportWriter.writeReport(writer, exception);
    110        } finally
    111        {
    112            InternalUtils.close(writer);
    113        }
    114    }
    115
    116
    117}