11//
22// CPLStar.swift
3- // Version: 1.6 .0
3+ // Version: 1.7 .0
44//
55// Standalone ConsolePerseusLogger.
66//
2727// Copyright © 7531 - 7534 PerseusRealDeal
2828//
2929// The year starts from the creation of the world according to a Slavic calendar.
30- // September, the 1st of Slavic year.
30+ // September, the 1st of Slavic year. It means that "Sep 01, 2025" is the beginning of 7534.
3131//
3232// Permission is hereby granted, free of charge, to any person obtaining a copy
3333// of this software and associated documentation files (the "Software"), to deal
@@ -62,6 +62,63 @@ protocol PerseusDelegatedMessage: AnyObject {
6262 var message : String { get set }
6363}
6464
65+ public struct LogMessage {
66+
67+ public let text : String
68+ public let level : PerseusLogger . Level
69+ public let localTime : PerseusLogger . LocalTime
70+ public let owner : PerseusLogger . PIDandTID
71+ public let user : PerseusLogger . User
72+ public let fileline : PerseusLogger . Directives
73+
74+ public func getMessage( mode: PerseusLogger . LineMode = . singleLine) -> String {
75+
76+ var tags = " "
77+
78+ // Type.
79+
80+ let isTyped =
81+ ( log. format == . full) ? true : log. marks && ( log. format != . textonly)
82+
83+ tags = isTyped ? " \( level. tag) " : tags
84+
85+ // Time.
86+
87+ let isTimed =
88+ ( log. format == . full) ? true : log. marks && log. time && ( log. format != . textonly)
89+
90+ if isTimed {
91+ let tag = " [ \( localTime. date) ] [ \( localTime. time) ] "
92+ tags = tags. isEmpty ? " \( tag) " : " \( tags) \( tag) "
93+ }
94+
95+ // PID and TID.
96+
97+ let withOwnerId =
98+ ( log. format == . full) ? true : log. owner && ( log. format != . textonly)
99+
100+ if withOwnerId {
101+ let tag = " [ \( owner. pid) : \( owner. tid) ] "
102+ tags = tags. isEmpty ? " \( tag) " : " \( tags) \( tag) "
103+ }
104+
105+ // Path.
106+
107+ let withPath =
108+ ( log. format == . full) ? true : log. directives && ( log. format != . textonly)
109+
110+ let messageText =
111+ withPath ? " \( text) , file: \( fileline. fileName) , line: \( fileline. line) " : " \( text) "
112+
113+ switch mode {
114+ case . singleLine:
115+ return tags. isEmpty ? " \( messageText) " : " \( tags) \( messageText) "
116+ case . multiLine:
117+ return tags. isEmpty ? " \( messageText) " : " \( tags) \r \n \( messageText) "
118+ }
119+ }
120+ }
121+
65122public class PerseusLogger {
66123
67124 // MARK: - Typealiases
@@ -71,9 +128,7 @@ public class PerseusLogger {
71128 public typealias PIDandTID = ( pid: String , tid: String ) // PID and Thread ID.
72129 public typealias Directives = ( fileName: String , line: UInt ) // #file and #line.
73130
74- public typealias MessageDelegate = (
75- ( String , Level , LocalTime , PIDandTID , User , Directives ) -> Void
76- )
131+ public typealias MessageDelegate = ( ( _ instance: LogMessage ) -> Void )
77132
78133 // MARK: - Constants
79134
@@ -90,7 +145,7 @@ public class PerseusLogger {
90145 public enum Output : String , Decodable , CaseIterable {
91146 case standard // In Use: Swift.print("").
92147 case consoleapp // In Use: Logger structure from iOS 14.0, macOS 11.0, NSLog otherwise.
93- case custom // In Use: customActionOnMessage?(_:_:_:_:_:_: ).
148+ case custom // In Use: customActionOnMessage?(_:).
94149 }
95150
96151 // log.message("Notification...", .notice, .custom, .enduser)
@@ -187,6 +242,11 @@ public class PerseusLogger {
187242// message
188243 }
189244
245+ public enum LineMode {
246+ case singleLine
247+ case multiLine
248+ }
249+
190250 // MARK: - Properties
191251
192252 public static var customActionOnMessage : PerseusLogger . MessageDelegate ?
@@ -207,6 +267,7 @@ public class PerseusLogger {
207267 // MARK: - Message Details Visibility Flags
208268
209269 public static var format = MessageFormat . short
270+ public static var linemode = LineMode . singleLine
210271
211272 // [TYPE] [DATE] [TIME] [PID:TID] message, file: #, line: #
212273 public static var marks = true // [TYPE]
@@ -270,52 +331,32 @@ public class PerseusLogger {
270331 return
271332 }
272333
273- var message = " "
274-
275- // Path.
334+ // Get message details.
276335
277- let withDirectives = ( format == . full) ? true : directives && ( format != . textonly)
278- let fileName = ( file. description as NSString ) . lastPathComponent
279-
280- if withDirectives {
281- message = " \( text ( ) ) , file: \( fileName) , line: \( line) "
282- } else {
283- message = " \( text ( ) ) "
284- }
285-
286- // PID and TID.
287-
288- let withOwnerId = ( format == . full) ? true : owner && ( format != . textonly)
289- let idTuple = getPIDandTID ( )
290-
291- if withOwnerId {
292- message = " [ \( idTuple. pid) : \( idTuple. tid) ] \( message) "
293- }
294-
295- // Time.
296-
297- let isTimed = ( format == . full) ? true : marks && time && ( format != . textonly)
298- let localTime = getLocalTime ( )
299-
300- if isTimed {
301- message = " [ \( localTime. date) ] [ \( localTime. time) ] \( message) "
302- }
303-
304- // Type.
305-
306- let isTyped = ( format == . full) ? true : marks && ( format != . textonly)
307- message = isTyped ? " \( type. tag) \( message) " : message
336+ let details = LogMessage (
337+ text: text ( ) ,
338+ level: type,
339+ localTime: getLocalTime ( ) ,
340+ owner: getPIDandTID ( ) ,
341+ user: user,
342+ fileline: ( fileName: ( file. description as NSString ) . lastPathComponent, line: line)
343+ )
308344
309345 // Print.
310346
311347 if oput == . custom {
312- let directives : Directives = ( fileName: fileName, line: line)
313- customActionOnMessage ? ( message, type, localTime, idTuple, user, directives)
348+ customActionOnMessage ? ( details)
314349 } else {
315- print ( message , type, oput)
350+ print ( details , type, oput)
316351 }
317352 }
318353
354+ }
355+
356+ // MARK: - Contract for CPL json config profile
357+
358+ extension PerseusLogger {
359+
319360 public static func loadConfig( _ profile: ProfileCPL ) -> Bool {
320361 if let data = profile. json. data ( using: . utf8) {
321362 if let jsonConfig = decodeJsonProfile ( data) {
@@ -345,12 +386,16 @@ public class PerseusLogger {
345386 log. message ( " CPL config file doesn't exist! " , . error)
346387 return false
347388 }
389+ }
390+
391+ // MARK: - Implementation
348392
349- // MARK: - Implementation
393+ extension PerseusLogger {
350394
351395 // swiftlint:disable:next cyclomatic_complexity
352- private static func print( _ text : String , _ type: Level , _ output: Output ) {
396+ private static func print( _ instance : LogMessage , _ type: Level , _ output: Output ) {
353397
398+ let text = instance. getMessage ( mode: log. linemode)
354399 let message = ( text: text, type: type)
355400
356401 if output == . standard {
@@ -663,6 +708,11 @@ extension PerseusLogger {
663708 }
664709
665710 public var text : String { report }
711+ public var linemode : LineMode = . singleLine {
712+ didSet {
713+ removeMessages ( )
714+ }
715+ }
666716
667717 // MARK: - Constants
668718
@@ -684,35 +734,32 @@ extension PerseusLogger {
684734
685735 // MARK: - Contract
686736
687- // swiftlint:disable:next function_parameter_count
688- public func report( _ text: String ,
689- _ type: Level ,
690- _ localTime: LocalTime ,
691- _ owner: PIDandTID ,
692- _ user: User ,
693- _ dirs: Directives ) {
737+ public func report( _ instance: LogMessage ) {
694738
695- let text = text. replacingOccurrences ( of: " \( type. tag) " , with: " " )
696- lastMessage = " [ \( localTime. date) ] [ \( localTime. time) ] \( type. tag) \r \n \( text) "
739+ lastMessage = instance. getMessage ( mode: self . linemode)
697740
698- if user == . enduser {
699- delegate? . message = text
741+ if instance . user == . enduser {
742+ delegate? . message = instance . text
700743 }
701744 }
702745
703746 public func clear( ) {
704- report = " "
747+ removeMessages ( )
705748 }
706749
707750 // MARK: - Realization
708751
752+ private func removeMessages( ) {
753+ report = " "
754+ }
755+
709756 private func resizeReportIfNeeded( ) {
710757
711758 let lmCount = lastMessage. count
712759 let nlCount = newLine. count
713760
714761 // Can the last message be reported?
715- guard lmCount != 0 , lmCount < limit else {
762+ guard lmCount != 0 , lmCount <= limit else {
716763 return
717764 }
718765
@@ -724,19 +771,19 @@ extension PerseusLogger {
724771
725772 // What length to remove?
726773 let messages = report. components ( separatedBy: newLine)
727- let messagesCount = messages. count - 1
774+ let messagesCount = messages. count
728775
729776 var lengthToRemove = 0
730777 var itemCount = 0
731778
732779 for item in messages {
733780
734781 itemCount += 1
735- let newLineLength = messagesCount == 0 ? 0 : nlCount
782+ let newLineLength = messagesCount == 1 ? 0 : nlCount
736783
737784 lengthToRemove += ( item. count + newLineLength)
738785
739- if itemCount == messagesCount, messagesCount > 2 {
786+ if itemCount == messagesCount, messagesCount >= 2 {
740787 lengthToRemove -= nlCount // There's no new line in the report end
741788 }
742789
@@ -760,7 +807,7 @@ extension PerseusLogger {
760807
761808 private func appendLastMessageToReport( ) {
762809
763- guard lastMessage. isEmpty == false , lastMessage. count < limit else {
810+ guard lastMessage. isEmpty == false , lastMessage. count <= limit else {
764811 return
765812 }
766813
0 commit comments