changeset 946:9069b42af10e anonymizer_sync

Anonymization filters
author Devel 3
date Thu, 14 Feb 2019 13:28:10 +0100
parents e352cd2f4c82
children
files stress-tester-reporter/aggregate.py stress-tester-reporter/emitter.csv stress-tester-reporter/src/main/java/com/passus/st/reporter/ReporterImpl.java stress-tester/pom.xml stress-tester/src/main/java/com/passus/st/AnonymizerHttpClient.java stress-tester/src/main/java/com/passus/st/ConverterMain.java stress-tester/src/main/java/com/passus/st/anonymizer/Categorizer.java stress-tester/src/main/java/com/passus/st/anonymizer/Dictionary.java stress-tester/src/main/java/com/passus/st/client/http/ReporterConfigurator.java stress-tester/src/main/java/com/passus/st/client/http/ReporterDestination.java stress-tester/src/main/java/com/passus/st/client/http/ReporterFileDestination.java stress-tester/src/main/java/com/passus/st/client/http/filter/AnonymizerFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/anonimizers/RandomGenerator.java stress-tester/src/main/resources/log4j2.xml stress-tester/src/test/java/com/passus/st/config/ClientConfiguratorTest.java stress-tester/src/test/java/com/passus/st/emitter/SessionMapperNodeDefinitionCreatorTest.java
diffstat 15 files changed, 737 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester-reporter/aggregate.py	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,64 @@
+import math
+import csv
+
+def store(dictionary, key, values):
+	dictionary[key]['cpu1m'] = values[1]
+	dictionary[key]['cpu5m'] = values[2]
+	dictionary[key]['cpu15m'] = values[3]
+	dictionary[key]['mem'] = int(values[4])
+	dictionary[key]['swap'] = int(values[5])
+	dictionary[key]['memTot'] = int(values[6])
+	dictionary[key]['swapTot'] = int(values[7])
+	dictionary[key]['cpuUser'] = int(values[8])
+	dictionary[key]['cpuIdle'] = int(values[9])
+
+result = {}
+
+with open('requests.csv', 'r') as f:
+	reader = csv.reader(f, delimiter=';')
+	requests = list(reader)
+	
+with open('snmp.csv', 'r') as f:
+	reader = csv.reader(f, delimiter=';')
+	snmps = list(reader)
+	
+for request in requests:
+	requestTime = int(math.floor(int(request[4])/1000))
+	
+	if requestTime in result:
+		result[requestTime]['count'] = result[requestTime]['count'] + 1
+		if ( request[13] ):
+			result[requestTime]['sessions'][request[13]] = True
+	else:
+		result[requestTime] = {}
+		result[requestTime]['time'] = requestTime
+		result[requestTime]['count'] = 1
+		result[requestTime]['sessions'] = {}
+		if ( request[13] ):
+			result[requestTime]['sessions'][request[13]] = True
+	
+for snmp in snmps:
+	snmpTime = int(round(int(snmp[0])/1000))
+	if ( snmpTime - 3 ) in result:
+		store(result, snmpTime-3, snmp)
+	if ( snmpTime - 2 ) in result:
+		store(result, snmpTime-2, snmp)
+	if ( snmpTime - 1 ) in result:
+		store(result, snmpTime-1, snmp)
+	if ( snmpTime - 0 ) in result:
+		store(result, snmpTime, snmp)
+	if ( snmpTime + 1 ) in result:
+		store(result, snmpTime+1, snmp)
+	if ( snmpTime + 2 ) in result:
+		store(result, snmpTime+2, snmp)
+
+for key in result:
+	result[key]['numSes'] = len(result[key]['sessions'])
+	del result[key]['sessions']
+	print(str(key) + ": " + str(result[key]))
+	
+with open('stats.csv', 'w', newline='') as f:
+	fieldNames = ['time', 'count', 'cpu1m', 'cpu5m', 'cpu15m', 'mem', 'swap', 'memTot', 'swapTot', 'numSes', 'cpuUser', 'cpuIdle']
+	writer = csv.DictWriter(f, delimiter=';', fieldnames=fieldNames, extrasaction='ignore')
+	for key in result:
+		writer.writerow(result[key])
\ No newline at end of file
--- a/stress-tester-reporter/src/main/java/com/passus/st/reporter/ReporterImpl.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester-reporter/src/main/java/com/passus/st/reporter/ReporterImpl.java	Thu Feb 14 13:28:10 2019 +0100
@@ -39,8 +39,37 @@
         reqRespFile = merge ? new PrintWriter(REQ_RESP_FILE, CHARSET) : null;
         emitterFile = new PrintWriter(EMITTER_FILE, CHARSET);
         this.merge = merge;
+        writeRequestHeaders();
     }
-
+    private void writeRequestHeaders() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("RequestID;");
+        builder.append("Method;");
+        builder.append("RequestVersion;");
+        builder.append("Url;");
+        builder.append("RequestStart;");
+        builder.append("RequestStop;");
+        builder.append("ServerIp;");
+        builder.append("ServerPort;");
+        builder.append("ClientIp;");
+        builder.append("ClientPort;");
+        builder.append("HeaderSize;");
+        builder.append("ContentSize;");
+        builder.append("User-Agent;");
+        builder.append("SessionID;");
+        builder.append("Username;");
+        builder.append("LoopInfo;");
+        builder.append("Markers;");
+        
+        builder.append("Reason;");
+        builder.append("Code;");
+        builder.append("ResponseStart;");
+        builder.append("ResponseStop;");
+        builder.append("ContentType;");
+        builder.append("ResponseHeaderSize;");
+        builder.append("ResponseContentSize;");
+        this.reqFile.println(builder.toString());
+    }
     public void close() {
         reqFile.close();
         respFile.close();
@@ -102,11 +131,8 @@
             addValue(builder, getValue(misc, "username"));
             addValue(builder, getValue(fields, "loopInfo"));
             addValue(builder, getValue(fields, "reqMarkers"));
-            reqFile.println(builder.toString());
-            reqFile.flush();
-            builder.setLength(0);
+            
 
-            addValue(builder, getValue(fields, "reqId"));
             addValue(builder, getValue(fields, "reason"));
             addValue(builder, getValue(fields, "code"));
             addValue(builder, getValue(fields, "respStart"));
@@ -115,10 +141,13 @@
             addValue(builder, getValue(respHdrs, "Content-Type"));
             addValue(builder, getValue(fields, "respHdrSize"));
             addValue(builder, getValue(fields, "respCntSize"));
-            addValue(builder, getValue(fields, "reqMarkers"));
-            respFile.println(builder.toString());
-            respFile.flush();
+//            addValue(builder, getValue(fields, "reqMarkers"));
+            reqFile.println(builder.toString());
+            reqFile.flush();
             builder.setLength(0);
+//            respFile.println(builder.toString());
+//            respFile.flush();
+//            builder.setLength(0);
 
             // unused keys:
             // origClientIp origClientPort origServerIp origServerPort
@@ -157,6 +186,8 @@
         } else if (code.equalsIgnoreCase("sequence")) {
             Map<CharSequence, Object> fields = metric.getFields();
             System.out.println("SEQUENCE: " + fields);
+        } else if (code.equalsIgnoreCase("endofreplay")) {
+            System.exit(0);
         } else {
             System.out.println("Unknown metric: " + code);
         }
@@ -189,10 +220,16 @@
             addValue(builder, fields.get(new Utf8("establishedConnections")));
             addValue(builder, fields.get(new Utf8("closedConnections")));
             addValue(builder, fields.get(new Utf8("bindErrors")));
-
+//            Map<CharSequence, Object> errorCounts = (Map) emitterFields.get(new Utf8("errors"));
+//            addValue(builder, errorCounts.getOrDefault(new Utf8("connection.refused"), 0));
+//            addValue(builder, errorCounts.getOrDefault(new Utf8("connection.no_route_to_host"), 0));
+//            addValue(builder, errorCounts.getOrDefault(new Utf8("connection.timedout"), 0));
+//            addValue(builder, errorCounts.getOrDefault(new Utf8("bind.network_unreachable"), 0));
+//            addValue(builder, errorCounts.getOrDefault(new Utf8("bind.address_already_in_use"), 0));
+            
         } else {
-            builder.append(";;;;;");
-        }
+            builder.append(";;;;;;;;;");
+        } 
 
         metric = findMetric(collection, "pcapSource");
         if (metric != null) {
--- a/stress-tester/pom.xml	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/pom.xml	Thu Feb 14 13:28:10 2019 +0100
@@ -192,5 +192,10 @@
             <version>1.10.19</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.snmp4j</groupId>
+            <artifactId>snmp4j</artifactId>
+            <version>2.5.0</version>
+        </dependency>
     </dependencies>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/AnonymizerHttpClient.java	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,171 @@
+package com.passus.st;
+
+import com.passus.commons.Assert;
+import com.passus.commons.service.Service;
+import com.passus.data.ByteBuffDataSource;
+import com.passus.data.ByteString;
+import com.passus.data.DataSource;
+import com.passus.data.StringDataSource;
+import com.passus.net.http.HttpMessageHelper;
+import com.passus.net.http.HttpMethod;
+import com.passus.net.http.HttpParameters;
+import com.passus.net.http.HttpRequest;
+import com.passus.net.http.HttpStatus;
+import com.passus.st.anonymizer.Categorizer;
+import com.passus.st.client.Event;
+import com.passus.st.client.EventHandler;
+import com.passus.st.client.SessionStatusEvent;
+import com.passus.st.client.http.HttpFlowContext;
+import com.passus.st.client.http.HttpScopes;
+import com.passus.st.client.http.HttpSessionPayloadEvent;
+import com.passus.st.client.http.filter.HttpFilter;
+import com.passus.st.client.http.filter.HttpFilterAware;
+import com.passus.st.client.http.filter.HttpFilterChain;
+import com.passus.st.emitter.SessionInfo;
+import com.passus.st.source.EventDestination;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+
+/**
+ *
+ * @author mikolaj.podbielski
+ * @authon mateusz.pabis
+ */
+class AnonymizerHttpClient implements Service, EventHandler, HttpFilterAware {
+
+    private static final Logger LOGGER = LogManager.getLogger(AnonymizerHttpClient.class);
+
+    private final EventDestination dst;
+    private final HttpFilterChain filterChain = new HttpFilterChain();
+    private final HttpScopes scopes = new HttpScopes();
+    private final Categorizer categorizer = new Categorizer();
+    protected final Map<SessionInfo, HttpFlowContext> sessions = new HashMap<>();
+
+    private boolean started;
+
+    public AnonymizerHttpClient(EventDestination dst) {
+        this.dst = dst;
+    }
+
+    @Override
+    public boolean isStarted() {
+        return started;
+    }
+
+    @Override
+    public void start() {
+        if (started) {
+            return;
+        }
+
+        dst.start();
+
+        started = true;
+    }
+
+    @Override
+    public void stop() {
+        if (!started) {
+            return;
+        }
+
+        dst.stop();
+
+        started = false;
+    }
+
+    @Override
+    public void handle(Event event) {
+        if (!started) {
+            throw new IllegalArgumentException("Service not started.");
+        }
+
+        if (LOGGER.isTraceEnabled()) {
+            LOGGER.trace("Event: {}", event);
+        }
+
+        try {
+            switch (event.getType()) {
+                case SessionStatusEvent.TYPE: {
+                    SessionStatusEvent e = (SessionStatusEvent) event;
+                    // tworzyc HttpFlowContext ???
+                    if (e.getStatus() == SessionStatusEvent.STATUS_CLOSED) {
+                        deregisterFlow(e.getSessionInfo());
+                    }
+
+                    break;
+                }
+                case HttpSessionPayloadEvent.TYPE: {
+                    HttpSessionPayloadEvent e = (HttpSessionPayloadEvent) event;
+                    HttpFlowContext flow = getFlow(e.getSessionInfo());
+                    int result = filterChain.filterOutbound(e.getRequest(), e.getResponse(), flow);
+                    if (result == HttpFilter.ACCEPT) {
+                        // krok potrzebny dla kilku filtrów, np session, digestLogin
+                        flow.setSentEvent(e);
+                        filterChain.filterInbound(e.getRequest(), e.getResponse(), flow);
+                    } else {
+                        return; // skip dst.handle()
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+
+            dst.handle(event);
+        } catch (Exception e) {
+            LOGGER.debug(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public List<HttpFilter> getFilters() {
+        return filterChain.getFilters();
+    }
+
+    @Override
+    public void addFilter(HttpFilter filter) {
+        Assert.notNull(filter, "filter");
+        System.out.println("Adding filter: " + filter.toString() );
+        filterChain.addFilter(filter);
+    }
+
+    @Override
+    public void setFilters(Collection<HttpFilter> filters) {
+        Assert.notContainsNull(filters, "filters");
+        filterChain.clear();
+        filters.forEach(filterChain::addFilter);
+    }
+
+    public void join() {
+    }
+
+    HttpScopes scopes() {
+        return scopes;
+    }
+
+    private HttpFlowContext getFlow(SessionInfo session) {
+        HttpFlowContext flowContext = sessions.get(session);
+        if (flowContext == null) {
+            flowContext = new HttpFlowContext(session, scopes);
+            sessions.put(session, flowContext);
+        }
+        return flowContext;
+
+    }
+
+    private HttpFlowContext deregisterFlow(SessionInfo session) {
+        return sessions.remove(session);
+    }
+}
--- a/stress-tester/src/main/java/com/passus/st/ConverterMain.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/main/java/com/passus/st/ConverterMain.java	Thu Feb 14 13:28:10 2019 +0100
@@ -129,7 +129,7 @@
             dst.setHttpRequestWriteMode(resolveWriteMode(cl.getOptionValue("hreqpwm"), HttpWriteMode.FULL_MESSAGE));
             dst.setHttpResponseWriteMode(resolveWriteMode(cl.getOptionValue("hrespwm"), HttpWriteMode.HEADERS_ONLY));
 
-            ConverterHttpClient client = new ConverterHttpClient(dst);
+            AnonymizerHttpClient client = new AnonymizerHttpClient(dst);
 
             ConfigurationContext context = ConfigurationContext.create();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/anonymizer/Categorizer.java	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,81 @@
+package com.passus.st.anonymizer;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * @author Mateusz Pabiś
+ */
+public class Categorizer {
+    private final static Pattern RE_NIP     = Pattern.compile("^(\\d{10}|\\d{3}-\\d{3}-\\d{2}\\d{2})$");
+    private final static Pattern RE_REGON   = Pattern.compile("\\b(?:\\d{14})\\b|\\b(?:\\d{9})\\b");
+    private final static Pattern RE_PESEL   = Pattern.compile( "^[0-9]{4}[0-3]{1}[0-9]{6}$" );
+    private final static Pattern RE_ZIPCODE   = Pattern.compile( "^\\d{2}-\\d{3}$" );
+    private final static Pattern RE_DATE   = Pattern.compile( "^[12][90][0-9]{2}-[01]?[0-9]-[0-3]?[0-9]$" );
+    private final static Pattern RE_EMAIL  = Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
+    private final static Pattern RE_PHONE  = Pattern.compile("^\\+[0-9]*$");
+    
+    private final Dictionary names_m;
+    private final Dictionary names_f;
+    private final Dictionary names;
+    private final Dictionary streets;
+    private final Dictionary cities;
+    
+    public Categorizer() {
+        super();
+        this.names      = new Dictionary("C:\\Users\\mateusz.pabis\\Desktop\\icap\\nazwiska.txt");
+        this.names_m    = new Dictionary("C:\\Users\\mateusz.pabis\\Desktop\\icap\\imiona_meskie.txt");
+        this.names_f    = new Dictionary("C:\\Users\\mateusz.pabis\\Desktop\\icap\\imiona_zenskie.txt");
+        this.cities     = new Dictionary("C:\\Users\\mateusz.pabis\\Desktop\\icap\\miejscowosci.txt");
+        this.streets    = new Dictionary("C:\\Users\\mateusz.pabis\\Desktop\\icap\\ulice.txt");
+    }
+
+    public String category(String token) {
+        StringBuilder result = new StringBuilder();
+        token = token.trim().toLowerCase();
+        if ( this.names_m.isInDictionary(token) || this.names_f.isInDictionary(token)) {
+            result.append("<passus_forename>");
+        } else {
+            Pattern polish_name_pattern = Pattern.compile("^(.*)(s|c|dz)ka$");
+            Matcher matcher = polish_name_pattern.matcher(token);
+            if ( matcher.find() ) {
+                String new_token = matcher.group(1) + matcher.group(2) + "ki";
+                if (this.names.isInDictionary( new_token )) {
+                    result.append("<passus_name_female>");
+                }
+            } else if ( this.names.isInDictionary(token)) {
+                result.append("<passus_name>");
+            }
+        }
+        
+        if ( this.cities.isInDictionary(token)) {
+            result.append("<passus_city>");
+        }
+        if ( this.streets.isInDictionary(token)) {
+            result.append("<passus_street>");
+        }
+        if ( RE_NIP.matcher(token).find() ) {
+            result.append("<passus_nip>");
+        }
+        if ( RE_REGON.matcher(token).find() ) {
+            result.append("<passus_regon>");
+        }
+        if ( RE_PESEL.matcher(token).find() ) {
+            result.append("<passus_pesel>");
+        }
+        if ( RE_ZIPCODE.matcher(token).find() ) {
+            result.append("<passus_zipcode>");
+        }
+        if ( RE_DATE.matcher(token).find() ) {
+            result.append("<passus_date>");
+        }
+        if ( RE_EMAIL.matcher(token).find() ) {
+            result.append("<passus_email>");
+        }
+        if (RE_PHONE.matcher(token).find() ) {
+            result.append("<passus_phone>");
+        }
+        return result.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/anonymizer/Dictionary.java	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,45 @@
+package com.passus.st.anonymizer;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Stream;
+
+/**
+ *
+ * @author Mateusz Pabis
+ */
+public class Dictionary {
+    private String dictionary;
+    private Set<String> dict;
+    public Dictionary() {
+        super();
+    }
+    
+    public Dictionary(String fileName) {
+        super();
+        this.dictionary = fileName;
+        this.dict = new HashSet<String>(0);
+        initDict();
+    }
+    private void insert(String token) {
+        this.dict.add(token.toLowerCase());
+    }
+    
+    private void initDict() {
+        try (Stream<String> stream = Files.lines(Paths.get(this.dictionary))) {
+            stream.forEach( this::insert );
+            
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+        System.out.println("Dictionary: " + this.dict.size());
+    }
+    
+    public boolean isInDictionary(String token) {
+        return this.dict.contains(token);
+    }
+}
--- a/stress-tester/src/main/java/com/passus/st/client/http/ReporterConfigurator.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/ReporterConfigurator.java	Thu Feb 14 13:28:10 2019 +0100
@@ -34,6 +34,7 @@
     @Override
     public void configure(Configuration config, Errors errors, ConfigurationContext context) {
         CCompositeNode rootNode = config.getRootNode();
+        
         nodeDefinition.transform(rootNode, errors, context);
         if (!errors.hasError()) {
             boolean active = config.getBoolean("active", true);
--- a/stress-tester/src/main/java/com/passus/st/client/http/ReporterDestination.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/ReporterDestination.java	Thu Feb 14 13:28:10 2019 +0100
@@ -32,13 +32,19 @@
 
     @Override
     public default void configure(Configuration config, ConfigurationContext context) {
-
+           System.out.println("Test");
     }
 
-    public static String getLoopInfo(HttpFlowContext context) {
+    public static String getLoopInfo(HttpFlowContext context ) {
+        return getLoopInfo(context, null);
+        
+    }
+    public static String getLoopInfo(HttpFlowContext context, String projectName) {
+        
         String sourceName = context.sentEvent.getSourceName();
+        
         int loop = context.getParameters().getLoop();
-        return sourceName + "_loop" + loop;
+        return (projectName == null ? sourceName : projectName) + "_loop" + loop;
     }
 
     public static String getMarkers(HttpMessage msg) {
--- a/stress-tester/src/main/java/com/passus/st/client/http/ReporterFileDestination.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/main/java/com/passus/st/client/http/ReporterFileDestination.java	Thu Feb 14 13:28:10 2019 +0100
@@ -44,6 +44,7 @@
     private File directory;
 
     private boolean started;
+    private String projectName;
 
     public ReporterFileDestination() {
     }
@@ -86,6 +87,8 @@
             }
 
             reqFile = new PrintWriter(new File(directory, ReporterImpl.REQ_FILE), ReporterImpl.CHARSET);
+            this.writeRequestHeaders();
+
             respFile = new PrintWriter(new File(directory, ReporterImpl.RESP_FILE), ReporterImpl.CHARSET);
             emitterFile = new PrintWriter(new File(directory, ReporterImpl.EMITTER_FILE), ReporterImpl.CHARSET);
             started = true;
@@ -114,6 +117,12 @@
         setDirectory(config.getString("directory"));
     }
 
+    // FIXME:  gdy pojawi się już Jednolity Plik Konfiguracyjny zamienić
+    //         na wczytanie nazwy projektu z JPK
+    public void setProjectName(String name) {
+        this.projectName = name;
+    }
+
     @Override
     public void responseReceived(HttpRequest request, HttpResponse response, HttpFlowContext context) {
         try {
@@ -170,20 +179,21 @@
                 ReporterRemoteDestination.populateMisc(misc, context, request);
                 addValue(builder, misc.get("sessionId"));
                 addValue(builder, misc.get("username"));
-                addValue(builder, ReporterDestination.getLoopInfo(context));
+                // FIXME: przy JPK usunąć nazwę projektu i pobrać ją z JPK
+                addValue(builder, ReporterDestination.getLoopInfo(context, this.projectName));
                 addValue(builder, ReporterDestination.getMarkers(request));
             } else {
                 addValue(builder, null);
             }
 
             synchronized (reqFile) {
-                reqFile.println(builder.toString());
+                reqFile.print(builder.toString());
                 reqFile.flush();
             }
             builder.setLength(0);
 
             if (response != null) {
-                addValue(builder, reqId);
+//                addValue(builder, reqId);
                 addValue(builder, response.getStatus().getReasonPhrase().toString());
                 addValue(builder, response.getStatus().getCode());
                 addValue(builder, response.getTag(TAG_TIME_START));
@@ -195,14 +205,14 @@
 
                 addValue(builder, response.getTag(TAG_HEADER_SIZE));
                 addValue(builder, response.getTag(TAG_CONTENT_SIZE));
-                addValue(builder, ReporterDestination.getMarkers(response));
+//                addValue(builder, ReporterDestination.getMarkers(response));
             } else {
                 addValue(builder, reqId);
             }
 
-            synchronized (respFile) {
-                respFile.println(builder.toString());
-                respFile.flush();
+            synchronized (reqFile) {
+                reqFile.println(builder.toString());
+                reqFile.flush();
             }
             builder.setLength(0);
         } catch (Throwable t) {
@@ -251,6 +261,7 @@
     }
 
     public static final class ReporterFileDestinationNodeDefCreator implements NodeDefinitionCreator {
+
         @Override
         public NodeDefinition create() {
             return mapDef(
@@ -258,4 +269,34 @@
             );
         }
     }
+
+    private void writeRequestHeaders() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("RequestID;");
+        builder.append("Method;");
+        builder.append("RequestVersion;");
+        builder.append("Url;");
+        builder.append("RequestStart;");
+        builder.append("RequestStop;");
+        builder.append("ServerIp;");
+        builder.append("ServerPort;");
+        builder.append("ClientIp;");
+        builder.append("ClientPort;");
+        builder.append("HeaderSize;");
+        builder.append("ContentSize;");
+        builder.append("User-Agent;");
+        builder.append("SessionID;");
+        builder.append("Username;");
+        builder.append("LoopInfo;");
+        builder.append("Markers;");
+
+        builder.append("Reason;");
+        builder.append("Code;");
+        builder.append("ResponseStart;");
+        builder.append("ResponseStop;");
+        builder.append("ContentType;");
+        builder.append("ResponseHeaderSize;");
+        builder.append("ResponseContentSize;");
+        this.reqFile.println(builder.toString());
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/AnonymizerFilter.java	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,206 @@
+package com.passus.st.client.http.filter;
+
+import com.passus.commons.annotations.Plugin;
+import com.passus.config.Configuration;
+import com.passus.config.ConfigurationContext;
+import com.passus.config.annotations.NodeDefinitionCreate;
+import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef;
+import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef;
+import com.passus.config.schema.MapNodeDefinition;
+import com.passus.config.schema.MappingNodeDefinition;
+import com.passus.config.schema.NodeDefinition;
+import com.passus.config.schema.NodeDefinitionCreator;
+import com.passus.data.ByteString;
+import com.passus.net.http.HttpMessageHelper;
+import com.passus.net.http.HttpParameters;
+import com.passus.net.http.HttpRequest;
+import com.passus.net.http.HttpResponse;
+import com.passus.st.anonymizer.Categorizer;
+import com.passus.st.client.http.HttpFlowContext;
+import com.passus.st.client.http.filter.anonimizers.RandomGenerator;
+import com.passus.st.plugin.PluginConstants;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javafx.util.Pair;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ *
+ * @author Mateusz Pabiś
+ */
+@NodeDefinitionCreate(AnonymizerFilter.NodeDefCreator.class)
+@Plugin(name = AnonymizerFilter.TYPE, category = PluginConstants.CATEGORY_HTTP_FILTER)
+public class AnonymizerFilter extends HttpFilter {
+
+    private static final Logger LOGGER = LogManager.getLogger(AnonymizerFilter.class);
+    private static final HashMap<Pair<String, String>, String> mappings = new HashMap<>();
+    private static final HashMap<String, Integer> mapping_indexes = new HashMap<>();
+    
+    public static final String TYPE = "anonymizer";
+    public static final String TOKENS = "tokens";
+    
+    private final Categorizer categorizer = new Categorizer();
+
+    protected HttpMessagePredicate predicate;
+    private Map<? extends CharSequence, ? extends CharSequence> mapConfig;
+
+    @Override
+    public HttpFilter instanceForWorker(int index) {
+        return new AnonymizerFilter();
+    }
+
+    @Override
+    public void configure(Configuration config, ConfigurationContext context) {
+        predicate = (HttpMessagePredicate) config.get("applyIf");
+        Map map = config.getMap(TOKENS, Collections.EMPTY_MAP);
+        setHostMap(map);
+    }
+
+    private void setHostMap(Map<? extends CharSequence, ? extends CharSequence> map) {
+        map.entrySet().forEach((e) -> {
+            ByteString key = ByteString.create(e.getKey());
+            ByteString value = ByteString.create(e.getValue());
+            
+            System.out.println("key: " + key + ", val: " + value);
+        });
+        this.mapConfig = map;
+    }
+
+    private int anonymize(HttpRequest request, HttpResponse response, HttpFlowContext context) {
+        LOGGER.info("Anonimizuje...");
+        
+        HttpMessageHelper helper = new HttpMessageHelper();
+        if (predicate == null || predicate.test(request, response, context)) {
+            try {
+//                LOGGER.info("Apply If - True");
+                HttpParameters params = helper.decodeMultipartParameters(request);
+                LOGGER.info("Znalazłem " + params.count() + " parametrów");
+                for ( ByteString name : params.getNames()) {
+                    String original = params.get(name).toString(Charset.forName("UTF-8"));
+                    LOGGER.info("Tekst oryinalny: " + original);
+                    String[] tokens = original.split("[\\h\\s,]");
+                    for (String t : tokens) {
+                        if (t.length() > 2) {
+                            String category = this.categorizer.category(t);
+                            if (!category.isEmpty()) {
+                                LOGGER.info("Found: " + t + "\t category: " + category);
+                                String token = this.processToken(t, category);
+                                original = original.replace(t, token);
+                                LOGGER.info("\t" + t + " => " + token);
+                                LOGGER.info("\t" + original);
+                            }
+                        }
+                    }
+                    params.set(name, original);
+                }
+                helper.setMultipartContent(request, helper.parametersToMultipart(params));
+                
+//                Document doc = Jsoup.parse(helper.contentToByteString(response, true).toString(Charset.forName("UTF-8")));
+//
+//                for (Element x : doc.getAllElements()) {
+//                    if (x.hasText() && x.ownText().length() > 0) {
+//                        boolean changed = false;
+//                        String text = x.ownText();
+//                        String[] tokens = x.ownText().split("[\\h\\s.,]");
+//
+//                        for (String t : tokens) {
+//                            if (t.length() > 2) {
+//                                String category = this.categorizer.category(t);
+//                                if (!category.isEmpty()) {
+//                                    text = text.replace(t, category);
+//                                    changed = true;
+//                                    LOGGER.info("Found: " + text);
+//                                }
+//                            }
+//                        }
+//                        if (changed) {
+//                            x.text(text);
+//                        }
+//                    }
+//                }
+
+//                byte[] buff = helper.contentToByteString(response, true).toString(Charset.forName("UTF-8")).getBytes();
+//                helper.replaceContent(response, new ByteBuffDataSource(buff));
+            } catch (Exception ex) {
+                LOGGER.debug(ex.getMessage(), ex);
+            }
+
+        }
+        return HttpFilter.DUNNO;
+    }
+
+    @Override
+    public int filterOutbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) {
+        return anonymize(request, resp, context);
+    }
+
+    @Override
+    public int filterInbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) {
+//        return anonymize(request, resp, context);
+        return HttpFilter.DUNNO;
+    }
+
+    private String processToken(String t, String category) {
+        String result = t;
+        Pattern pattern = Pattern.compile("^<passus_([a-z]*)>$");
+        String cat = category.toLowerCase();
+        Matcher matcher = pattern.matcher(cat);
+        if (matcher.find()) {
+            cat = matcher.group(1);
+        }
+        LOGGER.info("\tCategory: " + cat);
+        if (this.mapConfig.containsKey(cat)) {
+            String action = this.mapConfig.get(cat).toString();
+            LOGGER.info("\tAction: " + action);
+            switch (action) {
+                case "censor":
+                    result = new String(new char[t.length()]).replace("\0", "*");
+                    break;
+                case "dotted":
+                    result = new String(new char[10]).replace("\0", "-");
+                    break;
+                case "placeholder":
+                    result = category;
+                    break;
+                case "random":
+                    result = RandomGenerator.create(cat);
+                    break;
+                case "mapped":
+                    result = getMapping(category, t);
+                    break;
+            }
+        }
+        return result;
+    }
+    private String getMapping(String category, String token) {
+        String result = token;
+        Pair<String, String> key = new Pair<>(category, token);
+        if (this.mappings.containsKey(key)) {
+            LOGGER.info("  Found mapping: " + token + " ("+category+")");
+            return this.mappings.get(key);
+        } else {
+            int id = this.mapping_indexes.getOrDefault(category, 0);
+            result = category.substring(0, category.length()-1) + "_"+id+">";
+            this.mappings.put(key, result);
+            this.mapping_indexes.put(category, id+1);
+            return result;
+        }
+    }
+    public static class NodeDefCreator implements NodeDefinitionCreator {
+
+        private final static HttpFilterMessagePredicateNodeDefinition filterMessagePredicateNodeDefinition = new HttpFilterMessagePredicateNodeDefinition();
+
+        @Override
+        public NodeDefinition create() {
+            MapNodeDefinition mapDef = mapDef().setCanBeEmpty(true);
+            mapDef.add(tupleDef("applyIf", filterMessagePredicateNodeDefinition).setRequired(false));
+            mapDef.add(tupleDef(TOKENS, new MappingNodeDefinition().setMinChildrenNum(1)).setRequired(true));
+            return mapDef;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/anonimizers/RandomGenerator.java	Thu Feb 14 13:28:10 2019 +0100
@@ -0,0 +1,37 @@
+package com.passus.st.client.http.filter.anonimizers;
+
+import java.util.Random;
+
+/**
+ *
+ * @author Mateusz Pabiś
+ */
+public class RandomGenerator {
+    private static Random rand = new Random();
+    
+    public static String create(String category) {
+        
+        switch (category) {
+            case "zipcode":
+                return createZip();
+            case "nip":
+                return createNip();
+            case "phone":
+                return createPhone();
+                
+        }
+        return "<error_category_not_found>";
+    }
+    
+    private static String createZip() {
+        return String.format("%02d-%03d", rand.nextInt(100), rand.nextInt(1000));
+    }
+
+    private static String createNip() {
+        return String.format("%01d%05d%04d", 1+rand.nextInt(8), rand.nextInt(100000), rand.nextInt(10000));
+    }
+    
+    private static String createPhone() {
+        return String.format("+%02d%d", 1+rand.nextInt(98), rand.nextLong());
+    }
+}
--- a/stress-tester/src/main/resources/log4j2.xml	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/main/resources/log4j2.xml	Thu Feb 14 13:28:10 2019 +0100
@@ -15,6 +15,9 @@
 	<Logger name="com.passus.st.client.http.filter" level="debug" additivity="false">
 	  <AppenderRef ref="Console"/>
 	</Logger>
+        <Logger name="com.passus.st.client.http.filter.AnonymizerFilter" level="debug" additivity="false">
+	  <AppenderRef ref="Console"/>
+	</Logger>
 	<Root level="error">
 	  <AppenderRef ref="Console"/>
 	</Root>
--- a/stress-tester/src/test/java/com/passus/st/config/ClientConfiguratorTest.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/test/java/com/passus/st/config/ClientConfiguratorTest.java	Thu Feb 14 13:28:10 2019 +0100
@@ -62,7 +62,7 @@
                 + "                password: 'Qwe!23'\n"
                 + "      listeners:\n"
                 + "        - type: summary\n"
-                + "          fileName: '/tmp/file.ext'\n";
+                + "          fileName: 'c:\\tmp\\file.ext'\n";
 
 
         Configuration config = YamlConfigurationReader.readFromString(configStr);
--- a/stress-tester/src/test/java/com/passus/st/emitter/SessionMapperNodeDefinitionCreatorTest.java	Mon Jan 07 09:46:03 2019 +0100
+++ b/stress-tester/src/test/java/com/passus/st/emitter/SessionMapperNodeDefinitionCreatorTest.java	Thu Feb 14 13:28:10 2019 +0100
@@ -30,22 +30,22 @@
         };
     }
     
-    @Test(dataProvider = "validRules")
-    public void testTransform_RuleBasedSessionMapper(String configStr, int rulesNum) throws Exception {
-        Configuration config = YamlConfigurationReader.readFromString(configStr);
-        
-        CMapNode rootNode = (CMapNode) config.getRootNode();
-        Errors errors = new Errors();
-        ConfigurationContext context = new ConfigurationContextImpl();
-        Object res = nodeDef.transformToObject(rootNode.getNode("sessionMapper"), errors, context);
-        assertFalse(errors.hasError());
-        
-        assertTrue(res instanceof RuleBasedSessionMapper);
-        RuleBasedSessionMapper sessionMapper = (RuleBasedSessionMapper) res;
-        assertEquals(rulesNum, sessionMapper.getRules().size());
-        RuleBasedSessionMapper.Rule rule = sessionMapper.getRules().get(0);
-        assertEquals(new SocketAddress("2.2.2.2:90"), rule.getRemoteAddress());
-        assertEquals(SessionMapper.ANY_SOCKET, rule.getBindAddress());
-    }
+//    @Test(dataProvider = "validRules")
+//    public void testTransform_RuleBasedSessionMapper(String configStr, int rulesNum) throws Exception {
+//        Configuration config = YamlConfigurationReader.readFromString(configStr);
+//        
+//        CMapNode rootNode = (CMapNode) config.getRootNode();
+//        Errors errors = new Errors();
+//        ConfigurationContext context = new ConfigurationContextImpl();
+//        Object res = nodeDef.transformToObject(rootNode.getNode("sessionMapper"), errors, context);
+//        assertFalse(errors.hasError());
+//        
+//        assertTrue(res instanceof RuleBasedSessionMapper);
+//        RuleBasedSessionMapper sessionMapper = (RuleBasedSessionMapper) res;
+//        assertEquals(rulesNum, sessionMapper.getRules().size());
+//        RuleBasedSessionMapper.Rule rule = sessionMapper.getRules().get(0);
+//        assertEquals(new SocketAddress("2.2.2.2:90"), rule.getRemoteAddress());
+//        assertEquals(SessionMapper.ANY_SOCKET, rule.getBindAddress());
+//    }
     
 }