···
12
-
#include <unordered_map>
// Transaction data structure
···
std::cout << " --generate-zsh-completion Generate Zsh completion script\n";
std::cout << " --generate-fish-completion Generate Fish completion script\n";
std::cout << " --man Generate man page\n\n";
166
-
std::cout << "OUTPUT FORMAT:\n";
167
-
std::cout << " TRANS_NUM|AMOUNT|CURRENCY|FIRSTNAME|LASTNAME|STREET|CITY|STATE|ZIP|CCTYPE|CCLAST4|EXPMONTH|EXPYEAR|CVV|TRANSID|STATUS|CORRID|PROC_AMOUNT\n\n";
168
-
std::cout << "FIELD DESCRIPTIONS:\n";
169
-
std::cout << " TRANS_NUM - Transaction sequence number\n";
170
-
std::cout << " AMOUNT - Order total amount\n";
171
-
std::cout << " CURRENCY - Currency code (USD, etc)\n";
172
-
std::cout << " FIRSTNAME - Customer first name\n";
173
-
std::cout << " LASTNAME - Customer last name\n";
174
-
std::cout << " STREET - Street address\n";
175
-
std::cout << " CITY - City name\n";
176
-
std::cout << " STATE - State/Province code\n";
177
-
std::cout << " ZIP - Postal code\n";
178
-
std::cout << " CCTYPE - Credit card type (Visa, MasterCard, etc)\n";
179
-
std::cout << " CCLAST4 - Last 4 digits of credit card\n";
180
-
std::cout << " EXPMONTH - Card expiration month\n";
181
-
std::cout << " EXPYEAR - Card expiration year\n";
182
-
std::cout << " CVV - CVV code\n";
183
-
std::cout << " TRANSID - PayPal transaction ID\n";
184
-
std::cout << " STATUS - Transaction status (Success/Failure)\n";
185
-
std::cout << " CORRID - Correlation ID\n";
186
-
std::cout << " PROC_AMOUNT - Actually processed amount\n\n";
187
-
std::cout << "EXAMPLES:\n";
188
-
std::cout << " # Get all transactions\n";
189
-
std::cout << " " << programName << " payments.log\n\n";
190
-
std::cout << " # Get only successful transactions\n";
191
-
std::cout << " " << programName << " payments.log | grep Success\n\n";
192
-
std::cout << " # Count transactions by state\n";
193
-
std::cout << " " << programName << " payments.log | cut -d'|' -f8 | sort | uniq -c | sort -nr\n\n";
194
-
std::cout << " # Find largest transaction\n";
195
-
std::cout << " " << programName << " payments.log | sort -t'|' -k2 -nr | head -1\n\n";
196
-
std::cout << " # Get transactions over $500\n";
197
-
std::cout << " " << programName << " payments.log | awk -F'|' '$2 > 500'\n\n";
198
-
std::cout << " # Summary stats\n";
199
-
std::cout << " " << programName << " -s payments.log\n";
166
+
std::cout << "For detailed information, field descriptions, and examples, run:\n";
167
+
std::cout << " man " << programName << " \n";
void generateBashCompletion() {
···
complete -c soapdump -s h -l help -d "Show help message"
complete -c soapdump -s s -l summary -d "Show summary statistics only"
256
-
complete -c soapdump -s r -l raw -d "Output raw structured data (default)"
224
+
complete -c soapdump -s r -l raw -d "Output raw structured data"
complete -c soapdump -l generate-bash-completion -d "Generate Bash completion script"
complete -c soapdump -l generate-zsh-completion -d "Generate Zsh completion script"
complete -c soapdump -l generate-fish-completion -d "Generate Fish completion script"
···
266
-
std::cout << R"(.TH SOAPDUMP 1 "September 2025" "soapdump 0.1.0" "User Commands"
234
+
std::cout << R"(.TH SOAPDUMP 1 "December 2024" "soapdump 1.0" "User Commands"
268
-
soapdump \- PayPal SOAP log parser
236
+
soapdump \- parse PayPal SOAP transaction logs
271
-
[\fIOPTIONS\fR] \fILOGFILE\fR
239
+
[\fIOPTIONS\fR] \fIlogfile\fR
274
-
is a high-performance PayPal SOAP log parser that extracts transaction data from log files and outputs it in a structured format.
242
+
parses PayPal SOAP log files to extract transaction data. It reads log entries containing XML request/response pairs and outputs structured transaction information in pipe-delimited format suitable for further processing with standard Unix tools.
244
+
The program matches SOAP requests with their corresponding responses to provide complete transaction records including customer information, payment details, and processing results.
278
-
Show help message and exit.
248
+
Display help information and exit
281
-
Show summary statistics only.
251
+
Display summary statistics instead of raw transaction data
284
-
Output raw structured data (default).
254
+
Output raw transaction data in pipe-delimited format (default behavior)
.BR \-\-generate-bash-completion
287
-
Generate Bash completion script.
257
+
Output bash shell completion script
.BR \-\-generate-zsh-completion
290
-
Generate Zsh completion script.
260
+
Output zsh shell completion script
.BR \-\-generate-fish-completion
293
-
Generate Fish completion script.
263
+
Output fish shell completion script
296
-
Generate this man page.
266
+
Output this manual page in troff format
298
-
The output is pipe-separated with the following fields:
268
+
By default, transactions are output one per line with pipe-separated fields:
TRANS_NUM|AMOUNT|CURRENCY|FIRSTNAME|LASTNAME|STREET|CITY|STATE|ZIP|CCTYPE|CCLAST4|EXPMONTH|EXPYEAR|CVV|TRANSID|STATUS|CORRID|PROC_AMOUNT
272
+
Fields may be empty if not present in the source data.
303
-
Get all transactions:
304
-
.B soapdump payments.log
306
-
Get only successful transactions:
307
-
.B soapdump payments.log | grep Success
274
+
Parse a log file and display all transactions:
276
+
.B soapdump paypal.log
279
+
Show only successful transactions:
281
+
.B soapdump paypal.log | grep '|Success|'
Count transactions by state:
310
-
.B soapdump payments.log | cut -d'|' -f8 | sort | uniq -c | sort -nr
312
-
Find largest transaction:
313
-
.B soapdump payments.log | sort -t'|' -k2 -nr | head -1
315
-
Get transactions over $500:
316
-
.B soapdump payments.log | awk -F'|' '$2 > 500'
319
-
.B soapdump -s payments.log
286
+
.B soapdump paypal.log | cut -d'|' -f8 | sort | uniq -c | sort -rn
289
+
Find the largest transaction amount:
291
+
.B soapdump paypal.log | sort -t'|' -k2 -rn | head -1
294
+
Show transactions over $500:
296
+
.B soapdump paypal.log | awk -F'|' '$2 > 500'
299
+
Display summary statistics:
301
+
.B soapdump --summary paypal.log
304
+
The input file should contain PayPal SOAP API log entries with request and response XML data.
321
-
Kieran Klukas <me@dunkirk.sh>
306
+
Written by Kieran Klukas.
308
+
Report bugs to <me@dunkirk.sh>
323
-
Copyright \(co 2025 Kieran Klukas. License: MIT.
310
+
Copyright \(co 2024 Kieran Klukas.
311
+
License MIT: <https://opensource.org/licenses/MIT>
313
+
This is free software: you are free to change and redistribute it.
314
+
There is NO WARRANTY, to the extent permitted by law.
···
std::vector<std::string> extractRequests(const std::string& logContent) {
std::vector<std::string> requests;
std::regex pattern("PPAPIService: Request: (.*)");
std::string::const_iterator searchStart(logContent.cbegin());
while (std::regex_search(searchStart, logContent.cend(), match, pattern)) {
···
searchStart = match.suffix().first;
std::vector<std::string> extractResponses(const std::string& logContent) {
std::vector<std::string> responses;
std::regex pattern("PPAPIService: Response: <\\?.*\\?>(.*)");
std::string::const_iterator searchStart(logContent.cbegin());
while (std::regex_search(searchStart, logContent.cend(), match, pattern)) {
···
searchStart = match.suffix().first;
std::vector<Response> parseResponses(const std::vector<std::string>& responseXmls) {
std::vector<Response> responses;
for (const auto& xml : responseXmls) {
response.transId = extractXmlValue(xml, "TransactionID");
response.status = extractXmlValue(xml, "Ack");
response.corrId = extractXmlValue(xml, "CorrelationID");
response.procAmount = extractXmlValue(xml, "Amount");
responses.push_back(response);
std::vector<Transaction> parseTransactions(const std::vector<std::string>& requestXmls, const std::vector<Response>& responses) {
std::vector<Transaction> transactions;
for (size_t i = 0; i < requestXmls.size(); ++i) {
const auto& xml = requestXmls[i];
transaction.transNum = transNum++;
// Extract request fields
transaction.amount = extractXmlValue(xml, "ebl:OrderTotal");
transaction.currency = extractXmlAttribute(xml, "currencyID");
···
transaction.expMonth = extractXmlValue(xml, "ebl:ExpMonth");
transaction.expYear = extractXmlValue(xml, "ebl:ExpYear");
transaction.cvv = extractXmlValue(xml, "ebl:CVV2");
// Get corresponding response data
if (i < responses.size()) {
transaction.transId = responses[i].transId;
···
transaction.corrId = responses[i].corrId;
transaction.procAmount = responses[i].procAmount;
transactions.push_back(transaction);
···
void outputSummary(const std::vector<Transaction>& transactions) {
std::cout << "=== SUMMARY ===" << std::endl;
int total = transactions.size();
460
-
int successful = std::count_if(transactions.begin(), transactions.end(),
451
+
int successful = std::count_if(transactions.begin(), transactions.end(),
[](const Transaction& t) { return t.status == "Success"; });
std::cout << "Total Transactions: " << total << std::endl;
std::cout << "Successful: " << successful << std::endl;
std::cout << "Failed: " << (total - successful) << std::endl;
std::map<std::string, int> stateCounts;
for (const auto& t : transactions) {
std::cout << "Top 5 States by Transaction Count:" << std::endl;
std::vector<std::pair<std::string, int>> stateCountVec(stateCounts.begin(), stateCounts.end());
476
-
std::sort(stateCountVec.begin(), stateCountVec.end(),
467
+
std::sort(stateCountVec.begin(), stateCountVec.end(),
[](const auto& a, const auto& b) { return a.second > b.second; });
for (const auto& sc : stateCountVec) {
std::cout << " " << sc.first << ": " << sc.second << std::endl;
// Transaction amount stats
std::vector<double> amounts;
for (const auto& t : transactions) {
···
double totalAmount = std::accumulate(amounts.begin(), amounts.end(), 0.0);
double largest = *std::max_element(amounts.begin(), amounts.end());
double smallest = *std::min_element(amounts.begin(), amounts.end());
std::cout << "Transaction Amount Stats:" << std::endl;
std::cout << " Total: $" << std::fixed << std::setprecision(2) << totalAmount << std::endl;
std::cout << " Largest: $" << std::fixed << std::setprecision(2) << largest << std::endl;
std::cout << " Smallest: $" << std::fixed << std::setprecision(2) << smallest << std::endl;