mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
finally eliminating log spam; tidying up the decoded log files's format
This commit is contained in:
parent
284715d9a1
commit
bb95e8fe91
3 changed files with 83 additions and 23 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2020 PSForever
|
// Copyright (c) 2020 PSForever
|
||||||
package net.psforever.tools.decodePackets
|
package net.psforever.tools.decodePackets
|
||||||
|
|
||||||
import java.io.{File, IOException}
|
import java.io.{File, IOException, OutputStream, PrintStream}
|
||||||
import java.nio.charset.CodingErrorAction
|
import java.nio.charset.CodingErrorAction
|
||||||
import java.nio.file.{Files, Path, Paths, StandardCopyOption}
|
import java.nio.file.{Files, Path, Paths, StandardCopyOption}
|
||||||
import net.psforever.packet.PacketCoding
|
import net.psforever.packet.PacketCoding
|
||||||
|
|
@ -26,6 +26,12 @@ case class Config(
|
||||||
|
|
||||||
object DecodePackets {
|
object DecodePackets {
|
||||||
private val utf8Decoder = Codec.UTF8.decoder.onMalformedInput(CodingErrorAction.REPORT)
|
private val utf8Decoder = Codec.UTF8.decoder.onMalformedInput(CodingErrorAction.REPORT)
|
||||||
|
private val normalSystemOut = System.out
|
||||||
|
private val outCapture: PrintStream = new PrintStream(new OutputStream() {
|
||||||
|
@Override
|
||||||
|
@throws(classOf[Exception])
|
||||||
|
def write(arg0: Int): Unit = { }
|
||||||
|
})
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
val builder = OParser.builder[Config]
|
val builder = OParser.builder[Config]
|
||||||
|
|
@ -141,6 +147,8 @@ object DecodePackets {
|
||||||
* and those that can not.
|
* and those that can not.
|
||||||
* @param directory where the existing files may be found
|
* @param directory where the existing files may be found
|
||||||
* @param files files to test for matching names
|
* @param files files to test for matching names
|
||||||
|
* @see `filesWithSameNameAs`
|
||||||
|
* @see `getAllFilePathsFromDirectory`
|
||||||
* @return a tuple of file lists, comparing the param files against files in the directory;
|
* @return a tuple of file lists, comparing the param files against files in the directory;
|
||||||
* the first are the files whose names match;
|
* the first are the files whose names match;
|
||||||
* the second are the files whose names do not match
|
* the second are the files whose names do not match
|
||||||
|
|
@ -157,6 +165,7 @@ object DecodePackets {
|
||||||
* and those that can not.
|
* and those that can not.
|
||||||
* @param existingFiles files whose names are to test against
|
* @param existingFiles files whose names are to test against
|
||||||
* @param files files to test for matching names
|
* @param files files to test for matching names
|
||||||
|
* @see `lowercaseFileNameString`
|
||||||
* @return a tuple of file lists, comparing the param files against files in the directory;
|
* @return a tuple of file lists, comparing the param files against files in the directory;
|
||||||
* the first are the files whose names match;
|
* the first are the files whose names match;
|
||||||
* the second are the files whose names do not match
|
* the second are the files whose names do not match
|
||||||
|
|
@ -184,6 +193,9 @@ object DecodePackets {
|
||||||
/**
|
/**
|
||||||
* Enumerate over files found in the given directory for later.
|
* Enumerate over files found in the given directory for later.
|
||||||
* @param directory where the files are found
|
* @param directory where the files are found
|
||||||
|
* @see `Files.isDirectory`
|
||||||
|
* @see `Files.exists`
|
||||||
|
* @see `Paths.get`
|
||||||
* @return the discovered file paths
|
* @return the discovered file paths
|
||||||
*/
|
*/
|
||||||
private def getAllFilePathsFromDirectory(directory: String): Array[Path] = {
|
private def getAllFilePathsFromDirectory(directory: String): Array[Path] = {
|
||||||
|
|
@ -209,6 +221,9 @@ object DecodePackets {
|
||||||
* @param temporaryDirectory destination directory where files temporarily exist while being written
|
* @param temporaryDirectory destination directory where files temporarily exist while being written
|
||||||
* @param outDirectory destination directory where the files are stored after being written
|
* @param outDirectory destination directory where the files are stored after being written
|
||||||
* @param readDecodeAndWrite next step of the file decoding process
|
* @param readDecodeAndWrite next step of the file decoding process
|
||||||
|
* @see `Files.move`
|
||||||
|
* @see `Paths.get`
|
||||||
|
* @see `System.setOut`
|
||||||
*/
|
*/
|
||||||
private def decodeFilesUsing(
|
private def decodeFilesUsing(
|
||||||
files: Seq[File],
|
files: Seq[File],
|
||||||
|
|
@ -224,7 +239,9 @@ object DecodePackets {
|
||||||
val tmpDirPath = temporaryDirectory.getAbsolutePath + File.separator
|
val tmpDirPath = temporaryDirectory.getAbsolutePath + File.separator
|
||||||
val writer = writerConstructor(tmpDirPath, fileName)
|
val writer = writerConstructor(tmpDirPath, fileName)
|
||||||
try {
|
try {
|
||||||
|
System.setOut(outCapture)
|
||||||
readDecodeAndWrite(file, writer)
|
readDecodeAndWrite(file, writer)
|
||||||
|
System.setOut(normalSystemOut)
|
||||||
writer.close()
|
writer.close()
|
||||||
writer.getFileNames.foreach { fileNameWithExt =>
|
writer.getFileNames.foreach { fileNameWithExt =>
|
||||||
Files.move(Paths.get(tmpDirPath + fileNameWithExt), Paths.get(outDirPath + fileNameWithExt), StandardCopyOption.REPLACE_EXISTING)
|
Files.move(Paths.get(tmpDirPath + fileNameWithExt), Paths.get(outDirPath + fileNameWithExt), StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
|
@ -242,6 +259,11 @@ object DecodePackets {
|
||||||
* Read data from ASCII transcribed gcapy files.
|
* Read data from ASCII transcribed gcapy files.
|
||||||
* @param file file to read
|
* @param file file to read
|
||||||
* @param writer writer for output
|
* @param writer writer for output
|
||||||
|
* @see `decodeFileContents`
|
||||||
|
* @see `File.getAbsolutePath`
|
||||||
|
* @see `Source.fromFile`
|
||||||
|
* @see `Source.getLines`
|
||||||
|
* @see `Using`
|
||||||
*/
|
*/
|
||||||
private def preprocessed(file: File, writer: WriterWrapper): Unit = {
|
private def preprocessed(file: File, writer: WriterWrapper): Unit = {
|
||||||
Using(Source.fromFile(file.getAbsolutePath)(utf8Decoder)) { source =>
|
Using(Source.fromFile(file.getAbsolutePath)(utf8Decoder)) { source =>
|
||||||
|
|
@ -253,6 +275,11 @@ object DecodePackets {
|
||||||
* Read data from gcapy files.
|
* Read data from gcapy files.
|
||||||
* @param file file to read
|
* @param file file to read
|
||||||
* @param writer writer for output
|
* @param writer writer for output
|
||||||
|
* @see `decodeFileContents`
|
||||||
|
* @see `File.getAbsolutePath`
|
||||||
|
* @see `Source.fromFile`
|
||||||
|
* @see `Source.getLines`
|
||||||
|
* @see `Using`
|
||||||
*/
|
*/
|
||||||
private def gcapy(file: File, writer: WriterWrapper): Unit = {
|
private def gcapy(file: File, writer: WriterWrapper): Unit = {
|
||||||
Using(Source.fromString(s"gcapy -xa '${file.getAbsolutePath}'" !!)) { source =>
|
Using(Source.fromString(s"gcapy -xa '${file.getAbsolutePath}'" !!)) { source =>
|
||||||
|
|
@ -265,6 +292,10 @@ object DecodePackets {
|
||||||
* @param writer writer for output
|
* @param writer writer for output
|
||||||
* @param lines raw packet data from the source
|
* @param lines raw packet data from the source
|
||||||
* @throws java.io.IOException if writing data goes incorrectly
|
* @throws java.io.IOException if writing data goes incorrectly
|
||||||
|
* @see `decodePacket`
|
||||||
|
* @see `isNestedPacket`
|
||||||
|
* @see `recursivelyHandleNestedPacket`
|
||||||
|
* @see `shortGcapyString`
|
||||||
* @return number of lines read from the source
|
* @return number of lines read from the source
|
||||||
*/
|
*/
|
||||||
@throws(classOf[IOException])
|
@throws(classOf[IOException])
|
||||||
|
|
@ -276,15 +307,13 @@ object DecodePackets {
|
||||||
if (linesToSkip > 0) {
|
if (linesToSkip > 0) {
|
||||||
linesToSkip -= 1
|
linesToSkip -= 1
|
||||||
} else {
|
} else {
|
||||||
val decodedLine = decodePacket(
|
val header = shortGcapyString(line)
|
||||||
shortGcapyString(line),
|
val decodedLine = decodePacket(header, line.drop(line.lastIndexOf(' ')))
|
||||||
line.drop(line.lastIndexOf(' '))
|
|
||||||
)
|
|
||||||
writer.write(decodedLine)
|
writer.write(decodedLine)
|
||||||
val decodedLineText = decodedLine.text
|
val decodedLineText = decodedLine.text
|
||||||
if (isNestedPacket(decodedLineText)) {
|
if (isNestedPacket(decodedLineText)) {
|
||||||
// Packet with nested packets, including possibly other nested packets within e.g. SlottedMetaPacket containing a MultiPacketEx
|
// Packet with nested packets, including possibly other nested packets within e.g. SlottedMetaPacket containing a MultiPacketEx
|
||||||
val nestedLinesToSkip = recursivelyHandleNestedPacket(decodedLineText, writer)
|
val nestedLinesToSkip = recursivelyHandleNestedPacket(header, decodedLineText, writer)
|
||||||
// Gcapy output has duplicated lines for SlottedMetaPackets, so we can skip over those if found to reduce noise
|
// Gcapy output has duplicated lines for SlottedMetaPackets, so we can skip over those if found to reduce noise
|
||||||
// The only difference between the original and duplicate lines is a slight difference in timestamp of when the packet was processed
|
// The only difference between the original and duplicate lines is a slight difference in timestamp of when the packet was processed
|
||||||
linesToSkip = decodedLineText.indexOf("SlottedMetaPacket") match {
|
linesToSkip = decodedLineText.indexOf("SlottedMetaPacket") match {
|
||||||
|
|
@ -309,10 +338,16 @@ object DecodePackets {
|
||||||
* @param writer writer for output
|
* @param writer writer for output
|
||||||
* @param depth the number of layers to indent
|
* @param depth the number of layers to indent
|
||||||
* @throws java.io.IOException if writing data goes incorrectly
|
* @throws java.io.IOException if writing data goes incorrectly
|
||||||
|
* @see `decodePacket`
|
||||||
|
* @see `IOException`
|
||||||
|
* @see `isNestedPacket`
|
||||||
|
* @see `nested`
|
||||||
|
* @see `Regex.findAllIn`
|
||||||
* @return current indent layer
|
* @return current indent layer
|
||||||
*/
|
*/
|
||||||
@throws(classOf[IOException])
|
@throws(classOf[IOException])
|
||||||
private def recursivelyHandleNestedPacket(
|
private def recursivelyHandleNestedPacket(
|
||||||
|
header: String,
|
||||||
decodedLine: String,
|
decodedLine: String,
|
||||||
writer: WriterWrapper,
|
writer: WriterWrapper,
|
||||||
depth: Int = 0
|
depth: Int = 0
|
||||||
|
|
@ -323,16 +358,15 @@ object DecodePackets {
|
||||||
var linesToSkip = 0
|
var linesToSkip = 0
|
||||||
while (matches.hasNext) {
|
while (matches.hasNext) {
|
||||||
val packet = matches.next()
|
val packet = matches.next()
|
||||||
for (i <- depth to 0 by -1) {
|
for (_ <- depth until 0 by -1) {
|
||||||
if (i == 0) writer.write("> ")
|
writer.write(str = "-")
|
||||||
else writer.write("-")
|
|
||||||
}
|
}
|
||||||
val nextDecoded = decodePacket(decodedLine, packet)
|
writer.write(str = "> ")
|
||||||
|
val nextDecoded = nested(decodePacket(header, packet))
|
||||||
val nextDecodedLine = nextDecoded.text
|
val nextDecodedLine = nextDecoded.text
|
||||||
writer.write(nextDecoded)
|
writer.write(nextDecoded)
|
||||||
writer.newLine()
|
|
||||||
if (isNestedPacket(nextDecodedLine)) {
|
if (isNestedPacket(nextDecodedLine)) {
|
||||||
linesToSkip += recursivelyHandleNestedPacket(nextDecodedLine, writer, depth + 1)
|
linesToSkip += recursivelyHandleNestedPacket(header, nextDecodedLine, writer, depth + 1)
|
||||||
}
|
}
|
||||||
linesToSkip += 1
|
linesToSkip += 1
|
||||||
}
|
}
|
||||||
|
|
@ -366,14 +400,19 @@ object DecodePackets {
|
||||||
/**
|
/**
|
||||||
* Actually decode the packet data.
|
* Actually decode the packet data.
|
||||||
* @param hexString raw packet data
|
* @param hexString raw packet data
|
||||||
|
* @see `ByteVector.fromValidHex`
|
||||||
|
* @see `DecodeError`
|
||||||
|
* @see `DecodedPacket`
|
||||||
|
* @see `PacketCoding.decodePacket`
|
||||||
* @return decoded packet data
|
* @return decoded packet data
|
||||||
*/
|
*/
|
||||||
private def decodePacket(header: String, hexString: String): PacketOutput = {
|
private def decodePacket(header: String, hexString: String): PacketOutput = {
|
||||||
val byteVector = ByteVector.fromValidHex(hexString)
|
val byteVector = ByteVector.fromValidHex(hexString)
|
||||||
PacketCoding.decodePacket(byteVector) match {
|
val result = PacketCoding.decodePacket(byteVector) match {
|
||||||
case Successful(value) => DecodedPacket(header, value.toString.replace(",", ", "))
|
case Successful(value) => DecodedPacket(Some(header), value.toString.replace(",", ", "))
|
||||||
case Failure(cause) => DecodeError(header, s"Decoding error '${cause.toString}'")
|
case Failure(cause) => DecodeError(Some(header), s"Decoding error '${cause.toString}'")
|
||||||
}
|
}
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/** produce a wrapper that writes decoded packet data */
|
/** produce a wrapper that writes decoded packet data */
|
||||||
|
|
@ -381,6 +420,19 @@ object DecodePackets {
|
||||||
DecodeWriter(directoryPath, fileName)
|
DecodeWriter(directoryPath, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When nested, a normal properly decoded packet does not print header information.
|
||||||
|
* The header usually contains the original encoded hexadecimal string.
|
||||||
|
* @param in decoded packet data
|
||||||
|
* @return decoded packet data, potentially without header information
|
||||||
|
*/
|
||||||
|
private def nested(in: PacketOutput): PacketOutput = {
|
||||||
|
in match {
|
||||||
|
case DecodedPacket(_, text) if !in.text.contains("Decoding error") => DecodedPacket(header=None, text)
|
||||||
|
case _ => in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** produce a wrapper that writes decoded packet data and writes decode errors to a second file */
|
/** produce a wrapper that writes decoded packet data and writes decode errors to a second file */
|
||||||
private def errorWriter(directoryPath: String, fileName: String): WriterWrapper = {
|
private def errorWriter(directoryPath: String, fileName: String): WriterWrapper = {
|
||||||
DecodeErrorWriter(directoryPath, fileName)
|
DecodeErrorWriter(directoryPath, fileName)
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
package net.psforever.tools.decodePackets
|
package net.psforever.tools.decodePackets
|
||||||
|
|
||||||
trait PacketOutput {
|
trait PacketOutput {
|
||||||
def header: String
|
def header: Option[String]
|
||||||
def text: String
|
def text: String
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class DecodedPacket(header: String, text: String) extends PacketOutput
|
final case class DecodedPacket(header: Option[String], text: String) extends PacketOutput
|
||||||
|
|
||||||
final case class DecodeError(header: String, text: String) extends PacketOutput
|
final case class DecodeError(header: Option[String], text: String) extends PacketOutput
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,19 @@ final case class DecodeWriter(directoryPath: String, fileName: String) extends W
|
||||||
def write(str: String): Unit = log.write(str)
|
def write(str: String): Unit = log.write(str)
|
||||||
|
|
||||||
def write(data: PacketOutput): Unit = {
|
def write(data: PacketOutput): Unit = {
|
||||||
log.write(data.header)
|
data.header
|
||||||
log.newLine()
|
.collect { str =>
|
||||||
log.write(data.text)
|
log.write(str)
|
||||||
log.newLine()
|
log.newLine()
|
||||||
|
log.write(data.text)
|
||||||
|
log.newLine()
|
||||||
|
Some(str)
|
||||||
|
}
|
||||||
|
.orElse {
|
||||||
|
log.write(data.text)
|
||||||
|
log.newLine()
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def newLine(): Unit = log.newLine()
|
def newLine(): Unit = log.newLine()
|
||||||
|
|
@ -47,7 +56,6 @@ final case class DecodeErrorWriter(directoryPath: String, fileName: String)
|
||||||
|
|
||||||
def write(data: PacketOutput): Unit = {
|
def write(data: PacketOutput): Unit = {
|
||||||
log.write(data)
|
log.write(data)
|
||||||
log.newLine()
|
|
||||||
data match {
|
data match {
|
||||||
case error: DecodeError =>
|
case error: DecodeError =>
|
||||||
errorLog.write(error)
|
errorLog.write(error)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue