001/*
002 *  Copyright 2014 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016
017package org.ametys.plugins.core.ui.log;
018
019import java.io.File;
020import java.util.ArrayList;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.context.Context;
027import org.apache.avalon.framework.context.ContextException;
028import org.apache.avalon.framework.context.Contextualizable;
029import org.apache.cocoon.Constants;
030import org.apache.log4j.Appender;
031import org.apache.log4j.Logger;
032
033import org.ametys.core.ui.Callable;
034import org.ametys.runtime.log.MemoryAppender;
035import org.ametys.runtime.log.MemoryLogRecord;
036
037/**
038 * Manager for interacting with the MemoryAppender logs
039 */
040public class LogManager implements Component, Contextualizable
041{
042    /** The Avalon role */
043    public static final String ROLE = LogManager.class.getName();
044
045    /** Name of the memory appender */
046    public static final String MEMORY_APPENDER_NAME = "memory-appender";
047
048    private String _contextPath;
049    
050    @Override
051    public void contextualize(Context context) throws ContextException
052    {
053        org.apache.cocoon.environment.Context cocoonContext = (org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
054        _contextPath = cocoonContext.getRealPath("/");
055        _contextPath = _contextPath.replace('\\', '/');
056        if (!_contextPath.endsWith(File.separator))
057        {
058            _contextPath += File.separator;
059        }
060        
061        _contextPath = "file:" + _contextPath;
062    }
063    
064    /**
065     * Get the existing target types
066     * @param timestamp Events after this timestamp will be retrieved
067     * @param categories Events will be filtered by these categories. If empty, all categories are accepted.
068     * @return the target types
069     */
070    @Callable
071    public List<Map<String, Object>> getEvents (Long timestamp, List<String> categories)
072    {
073        long timeDelimiter = 0;
074        if (timestamp != null)
075        {
076            // Add one millisecond to take only events that happened after the specified time.
077            timeDelimiter = timestamp + 1;
078        }
079        
080        Appender appender = Logger.getRootLogger().getAppender(MEMORY_APPENDER_NAME);
081        
082        if (appender == null || !(appender instanceof MemoryAppender))
083        {
084            throw new RuntimeException("Unable to get the Memory Appender from the root logger.");
085        }
086
087        MemoryAppender memoryAppender = (MemoryAppender) appender;
088        
089        List<MemoryLogRecord> recentEvents = memoryAppender.getEvents(timeDelimiter, categories);
090        
091        List<Map<String, Object>> events = new ArrayList<>();
092        
093        for (MemoryLogRecord event : recentEvents)
094        {
095            Map<String, Object> jsonEvent = new HashMap<>();
096            
097            jsonEvent.put("timestamp", event.getMillis());
098            jsonEvent.put("category", event.getCategory());
099            jsonEvent.put("message", _hideRealPaths(event.getMessage()));
100            jsonEvent.put("location", event.getLocation());
101            jsonEvent.put("callstack", _hideRealPaths(event.getThrownStackTrace()));
102            jsonEvent.put("level", event.getLevel().getLabel());
103            jsonEvent.put("thread", event.getThreadDescription());
104            jsonEvent.put("user", event.getUser());
105            jsonEvent.put("requestURI", event.getRequestURI());
106            
107            events.add(jsonEvent);
108        }
109        
110        return events;
111    }
112    
113    private String _hideRealPaths(String text)
114    {
115        if (text == null)
116        {
117            return text;
118        }
119        
120        return text.replace(_contextPath, "context:/");
121    }
122}