|
JMeter example source code file (CSVSaveService.java)
The JMeter CSVSaveService.java source code/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.jmeter.save; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Vector; import javax.swing.table.DefaultTableModel; import org.apache.commons.collections.map.LinkedMap; import org.apache.commons.lang.CharUtils; import org.apache.commons.lang.StringUtils; import org.apache.jmeter.assertions.AssertionResult; import org.apache.jmeter.reporters.ResultCollector; import org.apache.jmeter.samplers.SampleEvent; import org.apache.jmeter.samplers.SampleResult; import org.apache.jmeter.samplers.SampleSaveConfiguration; import org.apache.jmeter.samplers.StatisticalSampleResult; import org.apache.jmeter.util.JMeterUtils; import org.apache.jmeter.visualizers.Visualizer; import org.apache.jorphan.logging.LoggingManager; import org.apache.jorphan.reflect.Functor; import org.apache.jorphan.util.JMeterError; import org.apache.jorphan.util.JOrphanUtils; import org.apache.log.Logger; import org.apache.oro.text.regex.Pattern; import org.apache.oro.text.regex.PatternMatcherInput; import org.apache.oro.text.regex.Perl5Compiler; import org.apache.oro.text.regex.Perl5Matcher; /** * This class provides a means for saving/reading test results as CSV files. */ // For unit tests, @see TestCSVSaveService public final class CSVSaveService { private static final Logger log = LoggingManager.getLoggerForClass(); // --------------------------------------------------------------------- // XML RESULT FILE CONSTANTS AND FIELD NAME CONSTANTS // --------------------------------------------------------------------- private static final String DATA_TYPE = "dataType"; // $NON-NLS-1$ private static final String FAILURE_MESSAGE = "failureMessage"; // $NON-NLS-1$ private static final String LABEL = "label"; // $NON-NLS-1$ private static final String RESPONSE_CODE = "responseCode"; // $NON-NLS-1$ private static final String RESPONSE_MESSAGE = "responseMessage"; // $NON-NLS-1$ private static final String SUCCESSFUL = "success"; // $NON-NLS-1$ private static final String THREAD_NAME = "threadName"; // $NON-NLS-1$ private static final String TIME_STAMP = "timeStamp"; // $NON-NLS-1$ // --------------------------------------------------------------------- // ADDITIONAL CSV RESULT FILE CONSTANTS AND FIELD NAME CONSTANTS // --------------------------------------------------------------------- private static final String CSV_ELAPSED = "elapsed"; // $NON-NLS-1$ private static final String CSV_BYTES= "bytes"; // $NON-NLS-1$ private static final String CSV_THREAD_COUNT1 = "grpThreads"; // $NON-NLS-1$ private static final String CSV_THREAD_COUNT2 = "allThreads"; // $NON-NLS-1$ private static final String CSV_SAMPLE_COUNT = "SampleCount"; // $NON-NLS-1$ private static final String CSV_ERROR_COUNT = "ErrorCount"; // $NON-NLS-1$ private static final String CSV_URL = "URL"; // $NON-NLS-1$ private static final String CSV_FILENAME = "Filename"; // $NON-NLS-1$ private static final String CSV_LATENCY = "Latency"; // $NON-NLS-1$ private static final String CSV_ENCODING = "Encoding"; // $NON-NLS-1$ private static final String CSV_HOSTNAME = "Hostname"; // $NON-NLS-1$ private static final String CSV_IDLETIME = "IdleTime"; // $NON-NLS-1$ // Used to enclose variable name labels, to distinguish from any of the above labels private static final String VARIABLE_NAME_QUOTE_CHAR = "\""; // $NON-NLS-1$ // Initial config from properties static private final SampleSaveConfiguration _saveConfig = SampleSaveConfiguration.staticConfig(); // Date format to try if the time format does not parse as milliseconds // (this is the suggested value in jmeter.properties) private static final String DEFAULT_DATE_FORMAT_STRING = "MM/dd/yy HH:mm:ss"; // $NON-NLS-1$ private static final DateFormat DEFAULT_DATE_FORMAT = new SimpleDateFormat(DEFAULT_DATE_FORMAT_STRING); private static final String LINE_SEP = System.getProperty("line.separator"); // $NON-NLS-1$ /** * Private constructor to prevent instantiation. */ private CSVSaveService() { } /** * Read Samples from a file; handles quoted strings. * * @param filename input file * @param visualizer where to send the results * @param resultCollector the parent collector * @throws IOException */ public static void processSamples(String filename, Visualizer visualizer, ResultCollector resultCollector) throws IOException { BufferedReader dataReader = null; final boolean errorsOnly = resultCollector.isErrorLogging(); final boolean successOnly = resultCollector.isSuccessOnlyLogging(); try { dataReader = new BufferedReader(new FileReader(filename)); dataReader.mark(400);// Enough to read the header column names // Get the first line, and see if it is the header String line = dataReader.readLine(); if (line == null){ throw new IOException(filename+": unable to read header line"); } long lineNumber=1; SampleSaveConfiguration saveConfig = CSVSaveService.getSampleSaveConfiguration(line,filename); if (saveConfig == null) {// not a valid header log.info(filename+" does not appear to have a valid header. Using default configuration."); saveConfig = (SampleSaveConfiguration) resultCollector.getSaveConfig().clone(); // may change the format later dataReader.reset(); // restart from beginning lineNumber = 0; } String [] parts; final char delim = saveConfig.getDelimiter().charAt(0); // TODO: does it matter that an empty line will terminate the loop? // CSV output files should never contain empty lines, so probably not // If so, then need to check whether the reader is at EOF while ((parts = csvReadFile(dataReader, delim)).length != 0) { lineNumber++; SampleEvent event = CSVSaveService.makeResultFromDelimitedString(parts,saveConfig,lineNumber); if (event != null){ final SampleResult result = event.getResult(); if (ResultCollector.isSampleWanted(result.isSuccessful(),errorsOnly, successOnly)) { visualizer.add(result); } } } } finally { JOrphanUtils.closeQuietly(dataReader); } } /** * Make a SampleResult given a set of tokens * @param parts tokens parsed from the input * @param saveConfig the save configuration (may be updated) * @param lineNumber * @return the sample result * * @throws JMeterError */ private static SampleEvent makeResultFromDelimitedString( final String[] parts, final SampleSaveConfiguration saveConfig, // may be updated final long lineNumber) { SampleResult result = null; String hostname = "";// $NON-NLS-1$ long timeStamp = 0; long elapsed = 0; String text = null; String field = null; // Save the name for error reporting int i=0; try { if (saveConfig.saveTimestamp()){ field = TIME_STAMP; text = parts[i++]; if (saveConfig.printMilliseconds()) { try { timeStamp = Long.parseLong(text); } catch (NumberFormatException e) {// see if this works log.warn(e.toString()); // method is only ever called from one thread at a time // so it's OK to use a static DateFormat Date stamp = DEFAULT_DATE_FORMAT.parse(text); timeStamp = stamp.getTime(); log.warn("Setting date format to: "+DEFAULT_DATE_FORMAT_STRING); saveConfig.setFormatter(DEFAULT_DATE_FORMAT); } } else if (saveConfig.formatter() != null) { Date stamp = saveConfig.formatter().parse(text); timeStamp = stamp.getTime(); } else { // can this happen? final String msg = "Unknown timestamp format"; log.warn(msg); throw new JMeterError(msg); } } if (saveConfig.saveTime()) { field = CSV_ELAPSED; text = parts[i++]; elapsed = Long.parseLong(text); } if (saveConfig.saveSampleCount()) { result = new StatisticalSampleResult(timeStamp, elapsed); } else { result = new SampleResult(timeStamp, elapsed); } if (saveConfig.saveLabel()) { field = LABEL; text = parts[i++]; result.setSampleLabel(text); } if (saveConfig.saveCode()) { field = RESPONSE_CODE; text = parts[i++]; result.setResponseCode(text); } if (saveConfig.saveMessage()) { field = RESPONSE_MESSAGE; text = parts[i++]; result.setResponseMessage(text); } if (saveConfig.saveThreadName()) { field = THREAD_NAME; text = parts[i++]; result.setThreadName(text); } if (saveConfig.saveDataType()) { field = DATA_TYPE; text = parts[i++]; result.setDataType(text); } if (saveConfig.saveSuccess()) { field = SUCCESSFUL; text = parts[i++]; result.setSuccessful(Boolean.valueOf(text).booleanValue()); } if (saveConfig.saveAssertionResultsFailureMessage()) { i++; // TODO - should this be restored? } if (saveConfig.saveBytes()) { field = CSV_BYTES; text = parts[i++]; result.setBytes(Integer.parseInt(text)); } if (saveConfig.saveThreadCounts()) { field = CSV_THREAD_COUNT1; text = parts[i++]; result.setGroupThreads(Integer.parseInt(text)); field = CSV_THREAD_COUNT2; text = parts[i++]; result.setAllThreads(Integer.parseInt(text)); } if (saveConfig.saveUrl()) { i++; // TODO: should this be restored? } if (saveConfig.saveFileName()) { field = CSV_FILENAME; text = parts[i++]; result.setResultFileName(text); } if (saveConfig.saveLatency()) { field = CSV_LATENCY; text = parts[i++]; result.setLatency(Long.parseLong(text)); } if (saveConfig.saveEncoding()) { field = CSV_ENCODING; text = parts[i++]; result.setEncodingAndType(text); } if (saveConfig.saveSampleCount()) { field = CSV_SAMPLE_COUNT; text = parts[i++]; result.setSampleCount(Integer.parseInt(text)); field = CSV_ERROR_COUNT; text = parts[i++]; result.setErrorCount(Integer.parseInt(text)); } if (saveConfig.saveHostname()) { field = CSV_HOSTNAME; hostname = parts[i++]; } if (saveConfig.saveIdleTime()) { field = CSV_IDLETIME; text = parts[i++]; result.setIdleTime(Long.parseLong(text)); } if (i + saveConfig.getVarCount() < parts.length){ log.warn("Line: "+lineNumber+". Found "+parts.length+" fields, expected "+i+". Extra fields have been ignored."); } } catch (NumberFormatException e) { log.warn("Error parsing field '" + field + "' at line " + lineNumber + " " + e); throw new JMeterError(e); } catch (ParseException e) { log.warn("Error parsing field '" + field + "' at line " + lineNumber + " " + e); throw new JMeterError(e); } catch (ArrayIndexOutOfBoundsException e){ log.warn("Insufficient columns to parse field '" + field + "' at line " + lineNumber); throw new JMeterError(e); } return new SampleEvent(result,"",hostname); } /** * Generates the field names for the output file * * @return the field names as a string */ public static String printableFieldNamesToString() { return printableFieldNamesToString(_saveConfig); } /** * Generates the field names for the output file * * @return the field names as a string */ public static String printableFieldNamesToString(SampleSaveConfiguration saveConfig) { StringBuilder text = new StringBuilder(); String delim = saveConfig.getDelimiter(); if (saveConfig.saveTimestamp()) { text.append(TIME_STAMP); text.append(delim); } if (saveConfig.saveTime()) { text.append(CSV_ELAPSED); text.append(delim); } if (saveConfig.saveLabel()) { text.append(LABEL); text.append(delim); } if (saveConfig.saveCode()) { text.append(RESPONSE_CODE); text.append(delim); } if (saveConfig.saveMessage()) { text.append(RESPONSE_MESSAGE); text.append(delim); } if (saveConfig.saveThreadName()) { text.append(THREAD_NAME); text.append(delim); } if (saveConfig.saveDataType()) { text.append(DATA_TYPE); text.append(delim); } if (saveConfig.saveSuccess()) { text.append(SUCCESSFUL); text.append(delim); } if (saveConfig.saveAssertionResultsFailureMessage()) { text.append(FAILURE_MESSAGE); text.append(delim); } if (saveConfig.saveBytes()) { text.append(CSV_BYTES); text.append(delim); } if (saveConfig.saveThreadCounts()) { text.append(CSV_THREAD_COUNT1); text.append(delim); text.append(CSV_THREAD_COUNT2); text.append(delim); } if (saveConfig.saveUrl()) { text.append(CSV_URL); text.append(delim); } if (saveConfig.saveFileName()) { text.append(CSV_FILENAME); text.append(delim); } if (saveConfig.saveLatency()) { text.append(CSV_LATENCY); text.append(delim); } if (saveConfig.saveEncoding()) { text.append(CSV_ENCODING); text.append(delim); } if (saveConfig.saveSampleCount()) { text.append(CSV_SAMPLE_COUNT); text.append(delim); text.append(CSV_ERROR_COUNT); text.append(delim); } if (saveConfig.saveHostname()) { text.append(CSV_HOSTNAME); text.append(delim); } if (saveConfig.saveIdleTime()) { text.append(CSV_IDLETIME); text.append(delim); } for (int i = 0; i < SampleEvent.getVarCount(); i++){ text.append(VARIABLE_NAME_QUOTE_CHAR); text.append(SampleEvent.getVarName(i)); text.append(VARIABLE_NAME_QUOTE_CHAR); text.append(delim); } String resultString = null; int size = text.length(); int delSize = delim.length(); // Strip off the trailing delimiter if (size >= delSize) { resultString = text.substring(0, size - delSize); } else { resultString = text.toString(); } return resultString; } // Map header names to set() methods private static final LinkedMap headerLabelMethods = new LinkedMap(); // These entries must be in the same order as columns are saved/restored. static { headerLabelMethods.put(TIME_STAMP, new Functor("setTimestamp")); headerLabelMethods.put(CSV_ELAPSED, new Functor("setTime")); headerLabelMethods.put(LABEL, new Functor("setLabel")); headerLabelMethods.put(RESPONSE_CODE, new Functor("setCode")); headerLabelMethods.put(RESPONSE_MESSAGE, new Functor("setMessage")); headerLabelMethods.put(THREAD_NAME, new Functor("setThreadName")); headerLabelMethods.put(DATA_TYPE, new Functor("setDataType")); headerLabelMethods.put(SUCCESSFUL, new Functor("setSuccess")); headerLabelMethods.put(FAILURE_MESSAGE, new Functor("setAssertionResultsFailureMessage")); headerLabelMethods.put(CSV_BYTES, new Functor("setBytes")); // Both these are needed in the list even though they set the same variable headerLabelMethods.put(CSV_THREAD_COUNT1,new Functor("setThreadCounts")); headerLabelMethods.put(CSV_THREAD_COUNT2,new Functor("setThreadCounts")); headerLabelMethods.put(CSV_URL, new Functor("setUrl")); headerLabelMethods.put(CSV_FILENAME, new Functor("setFileName")); headerLabelMethods.put(CSV_LATENCY, new Functor("setLatency")); headerLabelMethods.put(CSV_ENCODING, new Functor("setEncoding")); // Both these are needed in the list even though they set the same variable headerLabelMethods.put(CSV_SAMPLE_COUNT, new Functor("setSampleCount")); headerLabelMethods.put(CSV_ERROR_COUNT, new Functor("setSampleCount")); headerLabelMethods.put(CSV_HOSTNAME, new Functor("setHostname")); headerLabelMethods.put(CSV_IDLETIME, new Functor("setIdleTime")); } /** * Parse a CSV header line * @param headerLine from CSV file * @param filename name of file (for log message only) * @return config corresponding to the header items found or null if not a header line */ public static SampleSaveConfiguration getSampleSaveConfiguration(String headerLine, String filename){ String[] parts = splitHeader(headerLine,_saveConfig.getDelimiter()); // Try default delimiter String delim = null; if (parts == null){ Perl5Matcher matcher = JMeterUtils.getMatcher(); PatternMatcherInput input = new PatternMatcherInput(headerLine); Pattern pattern = JMeterUtils.getPatternCache() // This assumes the header names are all single words with no spaces // word followed by 0 or more repeats of (non-word char + word) // where the non-word char (\2) is the same // e.g. abc|def|ghi but not abd|def~ghi .getPattern("\\w+((\\W)\\w+)?(\\2\\w+)*(\\2\"\\w+\")*", // $NON-NLS-1$ // last entries may be quoted strings Perl5Compiler.READ_ONLY_MASK); if (matcher.matches(input, pattern)) { delim = matcher.getMatch().group(2); parts = splitHeader(headerLine,delim);// now validate the result } } if (parts == null) { return null; // failed to recognise the header } // We know the column names all exist, so create the config SampleSaveConfiguration saveConfig=new SampleSaveConfiguration(false); int varCount = 0; for(int i=0;i<parts.length;i++){ String label = parts[i]; if (isVariableName(label)){ varCount++; } else { Functor set = (Functor) headerLabelMethods.get(label); set.invoke(saveConfig,new Boolean[]{Boolean.TRUE}); } } if (delim != null){ log.warn("Default delimiter '"+_saveConfig.getDelimiter()+"' did not work; using alternate '"+delim+"' for reading "+filename); saveConfig.setDelimiter(delim); } saveConfig.setVarCount(varCount); return saveConfig; } private static String[] splitHeader(String headerLine, String delim) { String parts[]=headerLine.split("\\Q"+delim);// $NON-NLS-1$ int previous = -1; // Check if the line is a header for(int i=0;i<parts.length;i++){ final String label = parts[i]; // Check for Quoted variable names if (isVariableName(label)){ previous=Integer.MAX_VALUE; // they are always last continue; } int current = headerLabelMethods.indexOf(label); if (current == -1){ return null; // unknown column name } if (current <= previous){ log.warn("Column header number "+(i+1)+" name "+ label + " is out of order."); return null; // out of order } previous = current; } return parts; } /** * Check if the label is a variable name, i.e. is it enclosed in double-quotes? * * @param label column name from CSV file * @return if the label is enclosed in double-quotes */ private static boolean isVariableName(final String label) { return label.length() > 2 && label.startsWith(VARIABLE_NAME_QUOTE_CHAR) && label.endsWith(VARIABLE_NAME_QUOTE_CHAR); } /** * Method will save aggregate statistics as CSV. For now I put it here. * Not sure if it should go in the newer SaveService instead of here. * if we ever decide to get rid of this class, we'll need to move this * method to the new save service. * @param data vector of data rows * @param writer output file * @throws IOException */ public static void saveCSVStats(Vector<?> data, FileWriter writer) throws IOException { saveCSVStats(data, writer, null); } /** * Method will save aggregate statistics as CSV. For now I put it here. * Not sure if it should go in the newer SaveService instead of here. * if we ever decide to get rid of this class, we'll need to move this * method to the new save service. * @param data vector of data rows * @param writer output file * @param headers header names (if non-null) * @throws IOException */ public static void saveCSVStats(Vector<?> data, FileWriter writer, String headers[]) throws IOException { final char DELIM = ','; final char SPECIALS[] = new char[] {DELIM, QUOTING_CHAR}; if (headers != null){ for (int i=0; i < headers.length; i++){ if (i>0) { writer.write(DELIM); } writer.write(quoteDelimiters(headers[i],SPECIALS)); } writer.write(LINE_SEP); } for (int idx=0; idx < data.size(); idx++) { Vector<?> row = (Vector>)data.elementAt(idx); for (int idy=0; idy < row.size(); idy++) { if (idy > 0) { writer.write(DELIM); } Object item = row.elementAt(idy); writer.write( quoteDelimiters(String.valueOf(item),SPECIALS)); } writer.write(LINE_SEP); } } /** * Method saves aggregate statistics (with header names) as CSV from a table model. * Same as {@link #saveCSVStats(Vector, FileWriter, String[])} except * that there is no need to create a Vector containing the data. * * @param model table model containing the data * @param writer output file * @throws IOException */ public static void saveCSVStats(DefaultTableModel model, FileWriter writer) throws IOException { saveCSVStats(model, writer, true); } /** * Method saves aggregate statistics as CSV from a table model. * Same as {@link #saveCSVStats(Vector, FileWriter, String[])} except * that there is no need to create a Vector containing the data. * * @param model table model containing the data * @param writer output file * @param saveHeaders whether or not to save headers * @throws IOException */ public static void saveCSVStats(DefaultTableModel model, FileWriter writer, boolean saveHeaders) throws IOException { final char DELIM = ','; final char SPECIALS[] = new char[] {DELIM, QUOTING_CHAR}; final int columns = model.getColumnCount(); final int rows = model.getRowCount(); if (saveHeaders){ for (int i=0; i < columns; i++){ if (i>0) { writer.write(DELIM); } writer.write(quoteDelimiters(model.getColumnName(i),SPECIALS)); } writer.write(LINE_SEP); } for (int row=0; row < rows; row++) { for (int column=0; column < columns; column++) { if (column > 0) { writer.write(DELIM); } Object item = model.getValueAt(row, column); writer.write( quoteDelimiters(String.valueOf(item),SPECIALS)); } writer.write(LINE_SEP); } } /** * Convert a result into a string, where the fields of the result are * separated by the default delimiter. * * @param event * the sample event to be converted * @return the separated value representation of the result */ public static String resultToDelimitedString(SampleEvent event) { return resultToDelimitedString(event, event.getResult().getSaveConfig().getDelimiter()); } /** * Convert a result into a string, where the fields of the result are * separated by a specified String. * * @param event * the sample event to be converted * @param delimiter * the separation string * @return the separated value representation of the result */ public static String resultToDelimitedString(SampleEvent event, final String delimiter) { /* * Class to handle generating the delimited string. * - adds the delimiter if not the first call * - quotes any strings that require it */ final class StringQuoter{ final StringBuilder sb = new StringBuilder(); private final char[] specials; private boolean addDelim; public StringQuoter(char delim) { specials = new char[] {delim, QUOTING_CHAR, CharUtils.CR, CharUtils.LF}; addDelim=false; // Don't add delimiter first time round } private void addDelim(){ if (addDelim){ sb.append(specials[0]); } else { addDelim = true; } } // These methods handle parameters that could contain delimiters or quotes: public void append(String s){ addDelim(); //if (s == null) return; sb.append(quoteDelimiters(s,specials)); } public void append(Object obj){ append(String.valueOf(obj)); } // These methods handle parameters that cannot contain delimiters or quotes public void append(int i){ addDelim(); sb.append(i); } public void append(long l){ addDelim(); sb.append(l); } public void append(boolean b){ addDelim(); sb.append(b); } @Override public String toString(){ return sb.toString(); } } StringQuoter text = new StringQuoter(delimiter.charAt(0)); SampleResult sample = event.getResult(); SampleSaveConfiguration saveConfig = sample.getSaveConfig(); if (saveConfig.saveTimestamp()) { if (saveConfig.printMilliseconds()){ text.append(sample.getTimeStamp()); } else if (saveConfig.formatter() != null) { String stamp = saveConfig.formatter().format(new Date(sample.getTimeStamp())); text.append(stamp); } } if (saveConfig.saveTime()) { text.append(sample.getTime()); } if (saveConfig.saveLabel()) { text.append(sample.getSampleLabel()); } if (saveConfig.saveCode()) { text.append(sample.getResponseCode()); } if (saveConfig.saveMessage()) { text.append(sample.getResponseMessage()); } if (saveConfig.saveThreadName()) { text.append(sample.getThreadName()); } if (saveConfig.saveDataType()) { text.append(sample.getDataType()); } if (saveConfig.saveSuccess()) { text.append(sample.isSuccessful()); } if (saveConfig.saveAssertionResultsFailureMessage()) { String message = null; AssertionResult[] results = sample.getAssertionResults(); if (results != null) { // Find the first non-null message for (int i = 0; i < results.length; i++){ message = results[i].getFailureMessage(); if (message != null) { break; } } } if (message != null) { text.append(message); } else { text.append(""); // Need to append something so delimiter is added } } if (saveConfig.saveBytes()) { text.append(sample.getBytes()); } if (saveConfig.saveThreadCounts()) { text.append(sample.getGroupThreads()); text.append(sample.getAllThreads()); } if (saveConfig.saveUrl()) { text.append(sample.getURL()); } if (saveConfig.saveFileName()) { text.append(sample.getResultFileName()); } if (saveConfig.saveLatency()) { text.append(sample.getLatency()); } if (saveConfig.saveEncoding()) { text.append(sample.getDataEncodingWithDefault()); } if (saveConfig.saveSampleCount()) {// Need both sample and error count to be any use text.append(sample.getSampleCount()); text.append(sample.getErrorCount()); } if (saveConfig.saveHostname()) { text.append(event.getHostname()); } for (int i=0; i < SampleEvent.getVarCount(); i++){ text.append(event.getVarValue(i)); } return text.toString(); } // =================================== CSV quote/unquote handling ============================== /* * Private versions of what might eventually be part of Commons-CSV or Commons-Lang/Io... */ /* * <p> * Returns a <code>String value for a character-delimited column value * enclosed in the quote character, if required. * </p> * * <p> * If the value contains a special character, * then the String value is returned enclosed in the quote character. * </p> * * <p> * Any quote characters in the value are doubled up. * </p> * * <p> * If the value does not contain any special characters, * then the String value is returned unchanged. * </p> * * <p> * N.B. The list of special characters includes the quote character. * </p> * * @param input the input column String, may be null (without enclosing delimiters) * @param specialChars special characters; second one must be the quote character * @return the input String, enclosed in quote characters if the value contains a special character, * <code>null for null string input */ private static String quoteDelimiters(String input, char[] specialChars) { if (StringUtils.containsNone(input, specialChars)) { return input; } StringBuilder buffer = new StringBuilder(input.length() + 10); final char quote = specialChars[1]; buffer.append(quote); for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); if (c == quote) { buffer.append(quote); // double the quote char } buffer.append(c); } buffer.append(quote); return buffer.toString(); } // State of the parser private static final int INITIAL=0, PLAIN = 1, QUOTED = 2, EMBEDDEDQUOTE = 3; public static final char QUOTING_CHAR = '"'; /** * Reads from file and splits input into strings according to the delimiter, * taking note of quoted strings. * <p> * Handles DOS (CRLF), Unix (LF), and Mac (CR) line-endings equally. * <p> * N.B. a blank line is returned as a zero length array, whereas "" is returned * as an empty string. This is inconsistent. * @param infile input file - must support mark(1) * @param delim delimiter (e.g. comma) * @return array of strings * @throws IOException also for unexpected quote characters */ public static String[] csvReadFile(BufferedReader infile, char delim) throws IOException { int ch; int state = INITIAL; List<String> list = new ArrayList Other JMeter examples (source code examples)Here is a short list of links related to this JMeter CSVSaveService.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.