Skip to content

Commit

Permalink
Merge pull request #1 from tonystone/syslog-identifier
Browse files Browse the repository at this point in the history
Syslog identifier & Tag

Requested from tonystone/tracelog#44
  • Loading branch information
tonystone committed Jun 1, 2018
2 parents a4baf23 + b98c432 commit cf1f8fb
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 16 deletions.
16 changes: 12 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
/*.xcodeproj
/*.xcworkspace

## Build generated
build/
Expand Down Expand Up @@ -35,9 +36,9 @@ playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
Packages/
Package.pins
Package.resolved
.build/

# CocoaPods
Expand Down Expand Up @@ -66,3 +67,10 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Vagrant
.vagrant
Vagrantfile

# JetBrains products
.idea
46 changes: 43 additions & 3 deletions Sources/TraceLogJournalWriter/SDJournalWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public class SDJournalWriter: Writer {
.trace4: LOG_DEBUG
]

///
/// Override value for the systemd journal field SYSLOG_IDENTIFIER.
///
private let syslogIdentifier: String?

///
/// A dictionary keyed by TraceLog LogLevels with the value to convert to the sd-journals level.
///
Expand All @@ -52,9 +57,11 @@ public class SDJournalWriter: Writer {
/// Initializes an SDJournalWriter.
///
/// - Parameters:
/// - syslogIdentifier: A String override value for the systemd journal field SYSLOG_IDENTIFIER. If not passsed the journal will set it's default value.
/// - logLevelConversion: A dictionary keyed by TraceLog LogLevels with the value to convert to the os_log level.
///
public init(logLevelConversion: [LogLevel: SDJournalPriority] = SDJournalWriter.defaultLogLevelConversion) {
public init(syslogIdentifier: String? = nil, logLevelConversion: [LogLevel: SDJournalPriority] = SDJournalWriter.defaultLogLevelConversion) {
self.syslogIdentifier = syslogIdentifier
self.logLevelConversion = logLevelConversion
}

Expand All @@ -63,8 +70,19 @@ public class SDJournalWriter: Writer {
///
public func log(_ timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: RuntimeContext, staticContext: StaticContext) {

withVaList([]) { vaList -> Void in
sd_journal_printv_with_location(convertLogLevel(for: level), "CODE_FILE=\(staticContext.file)", "CODE_LINE=\(staticContext.line)", staticContext.function, message, vaList)
var elements = ["MESSAGE=\(message)",
"CODE_FILE=\(staticContext.file)",
"CODE_LINE=\(staticContext.line)",
"CODE_FUNC=\(staticContext.function)",
"PRIORITY=\(convertLogLevel(for: level))",
"TAG=\(tag)"]

if let identifier = self.syslogIdentifier {
elements.append("SYSLOG_IDENTIFIER=\(identifier)")
}

withIovecArray(elements) { array, count -> Void in
sd_journal_sendv(array, count)
}
}

Expand All @@ -80,4 +98,26 @@ public class SDJournalWriter: Writer {
return level
}
}

///
/// Helper function to convert an Array of strings into an array of iovec structs suitable for passing
/// to C level functions.
///
private func withIovecArray<R>(_ elements: [String], _ body: (UnsafePointer<iovec>, Int32) -> R) -> R {

var cStrings = elements.map { $0.utf8CString }

var iovecArray: [iovec] = []

for i in 0..<cStrings.count {
let len = cStrings[i].count - 1
cStrings[i].withUnsafeMutableBytes { (bytes) -> Void in
if let address = bytes.baseAddress {
iovecArray.append(iovec(iov_base: address, iov_len: len))
}
}
}
return body(&iovecArray, Int32(iovecArray.count))
}

#endif
1 change: 1 addition & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extension SDJournalWriterTests {
("testConvertLogLvelTrace2WithEmptyConversionTable", testConvertLogLvelTrace2WithEmptyConversionTable),
("testConvertLogLvelTrace3WithEmptyConversionTable", testConvertLogLvelTrace3WithEmptyConversionTable),
("testConvertLogLvelTrace4WithEmptyConversionTable", testConvertLogLvelTrace4WithEmptyConversionTable),
("testSyslogIdentifier",testSyslogIdentifier)

]
}
Expand Down
30 changes: 21 additions & 9 deletions Tests/TraceLogJournalWriterTests/SDJournalWriterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ class SDJournalWriterTests: XCTestCase {
XCTAssertEqual(SDJournalWriter(logLevelConversion: [:]).convertLogLevel(for: .trace4), LOG_INFO)
}

// MARK: - Init method tests

func testSyslogIdentifier() {
let syslogIdentifier = "TestSyslogIdentifier"

_testLog(for: .error, TestStaticContext(), SDJournalWriter(syslogIdentifier: syslogIdentifier), syslogIdentifier) { input, writer in

writer.log(input.timestamp, level: input.level, tag: input.tag, message: input.message, runtimeContext: input.runtimeContext, staticContext: input.staticContext)
}
}

// MARK: - Direct calls to the writer with default conversion table.

Expand Down Expand Up @@ -209,7 +219,7 @@ class TraceLogWithSDJournalWriterTests: XCTestCase {
///
///
///
private func _testLog(for level: LogLevel, _ staticContext: TestStaticContext, _ writer: SDJournalWriter, logBlock: ((timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: TestRuntimeContext, staticContext: TestStaticContext), SDJournalWriter) -> Void) {
private func _testLog(for level: LogLevel, _ staticContext: TestStaticContext, _ writer: SDJournalWriter, _ syslogIdentifier: String = "TraceLogJournalWriterPackageTests.xctest", logBlock: ((timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: TestRuntimeContext, staticContext: TestStaticContext), SDJournalWriter) -> Void) {

/// This is the time in microseconds since the epoch UTC to match the journals time stamps.
let timestamp = Date().timeIntervalSince1970 * 1000.0
Expand All @@ -220,7 +230,7 @@ private func _testLog(for level: LogLevel, _ staticContext: TestStaticContext, _
logBlock(input, writer)

do {
let found = try journalEntryExists(for: input, writer: writer)
let found = try journalEntryExists(for: input, writer: writer, syslogIdentifier: syslogIdentifier)

XCTAssertTrue(found)
} catch {
Expand All @@ -231,10 +241,10 @@ private func _testLog(for level: LogLevel, _ staticContext: TestStaticContext, _
///
/// Valdate that the log record is in the journal
///
private func journalEntryExists(for input: (timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: TestRuntimeContext, staticContext: TestStaticContext), writer: SDJournalWriter) throws -> Bool {
private func journalEntryExists(for input: (timestamp: Double, level: LogLevel, tag: String, message: String, runtimeContext: TestRuntimeContext, staticContext: TestStaticContext), writer: SDJournalWriter, syslogIdentifier: String) throws -> Bool {
let messageDate = Date(timeIntervalSince1970: input.timestamp / 1000.0)

let data = shell("journalctl -o json --identifier=TraceLogJournalWriterPackageTests.xctest --since='\(dateFormatter.string(from: messageDate))'")
let data = shell("journalctl -o json --identifier=\(syslogIdentifier) --since='\(dateFormatter.string(from: messageDate))'")

///
/// The journal entries are returned one JSON object per line so split the
Expand All @@ -254,11 +264,13 @@ private func journalEntryExists(for input: (timestamp: Double, level: LogLevel,
///
/// These should be all the fields we pass to systemd journal.
///
if journalEntry["PRIORITY"] as? String ?? "" == String(writer.convertLogLevel(for: input.level)) &&
journalEntry["CODE_FILE"] as? String ?? "" == input.staticContext.file &&
journalEntry["CODE_LINE"] as? String ?? "" == String(input.staticContext.line) &&
journalEntry["CODE_FUNC"] as? String ?? "" == input.staticContext.function &&
journalEntry["MESSAGE"] as? String ?? "" == input.message {
if journalEntry["SYSLOG_IDENTIFIER"] as? String ?? "" == syslogIdentifier &&
journalEntry["PRIORITY"] as? String ?? "" == String(writer.convertLogLevel(for: input.level)) &&
journalEntry["CODE_FILE"] as? String ?? "" == input.staticContext.file &&
journalEntry["CODE_LINE"] as? String ?? "" == String(input.staticContext.line) &&
journalEntry["CODE_FUNC"] as? String ?? "" == input.staticContext.function &&
journalEntry["MESSAGE"] as? String ?? "" == input.message &&
journalEntry["TAG"] as? String ?? "" == input.tag {

return true
}
Expand Down

0 comments on commit cf1f8fb

Please sign in to comment.