001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.log4j.rewrite;
018
019import org.apache.log4j.bridge.LogEventAdapter;
020import org.apache.log4j.helpers.OptionConverter;
021import org.apache.log4j.spi.LocationInfo;
022import org.apache.log4j.spi.LoggingEvent;
023import org.apache.logging.log4j.core.LogEvent;
024import org.apache.logging.log4j.core.impl.Log4jLogEvent;
025import org.apache.logging.log4j.message.SimpleMessage;
026import org.apache.logging.log4j.util.SortedArrayStringMap;
027
028import java.util.Collections;
029import java.util.HashMap;
030import java.util.Map;
031import java.util.StringTokenizer;
032
033/**
034 * This policy rewrites events by adding
035 * a user-specified list of properties to the event.
036 * Existing properties are not modified.
037 * <p>
038 * The combination of the RewriteAppender and this policy
039 * performs the same actions as the PropertyFilter from log4j 1.3.
040 * </p>
041 */
042public class PropertyRewritePolicy implements RewritePolicy {
043    private Map<String, String> properties = Collections.EMPTY_MAP;
044
045    public PropertyRewritePolicy() {
046    }
047
048    /**
049     * Set a string representing the property name/value pairs.
050     * <p>
051     * Form:
052     * </p>
053     * <pre>
054     * propname1=propvalue1,propname2=propvalue2
055     * </pre>
056     *
057     * @param properties The properties.
058     */
059    public void setProperties(String properties) {
060        Map<String, String> newMap = new HashMap<>();
061        StringTokenizer pairs = new StringTokenizer(properties, ",");
062        while (pairs.hasMoreTokens()) {
063            StringTokenizer entry = new StringTokenizer(pairs.nextToken(), "=");
064            newMap.put(entry.nextElement().toString().trim(), entry.nextElement().toString().trim());
065        }
066        synchronized (this) {
067            this.properties = newMap;
068        }
069    }
070
071    /**
072     * {@inheritDoc}
073     */
074    @Override
075    public LoggingEvent rewrite(final LoggingEvent source) {
076        if (!properties.isEmpty()) {
077            Map<String, String> rewriteProps = source.getProperties() != null ? new HashMap<>(source.getProperties())
078                    : new HashMap<>();
079            for (Map.Entry<String, String> entry : properties.entrySet()) {
080                if (!rewriteProps.containsKey(entry.getKey())) {
081                    rewriteProps.put(entry.getKey(), entry.getValue());
082                }
083            }
084            LogEvent event;
085            if (source instanceof LogEventAdapter) {
086                event = new Log4jLogEvent.Builder(((LogEventAdapter) source).getEvent())
087                        .setContextData(new SortedArrayStringMap(rewriteProps))
088                        .build();
089            } else {
090                LocationInfo info = source.getLocationInformation();
091                StackTraceElement element = new StackTraceElement(info.getClassName(), info.getMethodName(),
092                        info.getFileName(), Integer.parseInt(info.getLineNumber()));
093                Thread thread = getThread(source.getThreadName());
094                long threadId = thread != null ? thread.getId() : 0;
095                int threadPriority = thread != null ? thread.getPriority() : 0;
096                event = Log4jLogEvent.newBuilder()
097                        .setContextData(new SortedArrayStringMap(rewriteProps))
098                        .setLevel(OptionConverter.convertLevel(source.getLevel()))
099                        .setLoggerFqcn(source.getFQNOfLoggerClass())
100                        .setMarker(null)
101                        .setMessage(new SimpleMessage(source.getRenderedMessage()))
102                        .setSource(element)
103                        .setLoggerName(source.getLoggerName())
104                        .setThreadName(source.getThreadName())
105                        .setThreadId(threadId)
106                        .setThreadPriority(threadPriority)
107                        .setThrown(source.getThrowableInformation().getThrowable())
108                        .setTimeMillis(source.getTimeStamp())
109                        .setNanoTime(0)
110                        .setThrownProxy(null)
111                        .build();
112            }
113            return new LogEventAdapter(event);
114        }
115        return source;
116    }
117
118    private Thread getThread(String name) {
119        for (Thread thread : Thread.getAllStackTraces().keySet()) {
120            if (thread.getName().equals(name)) {
121                return thread;
122            }
123        }
124        return null;
125    }
126}