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}