Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Define the Chronicle output styles as nim-serialization formats #82

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

JohnAD
Copy link

@JohnAD JohnAD commented May 16, 2020

ref: #72

Ignore this first commit as I'm just playing around with the existing setup. I created an example chronicle stream similar to textLines.

I will be making a Writer next.

@zah I noticed that you have already taken the changes in the latest-fs branch and merged them into master. Should I redo this PR against latest-fs or stay here?

@zah
Copy link
Contributor

zah commented May 17, 2020

That's a good start, but please preserve all configurability that controls the use of colors and timestamps. On Windows, I think it's now reasonable for Chronicles to take advantage of the improved support for ANSI escape codes that was shipped 2 years ago:

https://stackoverflow.com/questions/16755142/how-to-make-win32-console-recognize-ansi-vt100-escape-sequences

Another expected outcome of the refactoring is that we'll be able to stop using memoryOutput() to buffer the generated log lines. Instead, we'll rely on the fsStdOut stream defined here:

https://github.com/status-im/nim-faststreams/blob/master/faststreams/stdout.nim

This stream will reuse a thread-local buffer and as a result most log lines will be generated and sent to the screen without any memory allocations.

Targeting master everywhere now is fine.

@JohnAD
Copy link
Author

JohnAD commented May 18, 2020

This latest commit won't work without a commit I made to my nim-faststreams fork that adds a writeTextQuoted function to textio.

I'm not convinced it is generic enough to belong there. I'll have to think about that a bit. If curious, it can be seen at https://github.com/JohnAD/nim-faststreams/blob/master/faststreams/textio.nim#L119

@zah
Copy link
Contributor

zah commented May 18, 2020

You are on the right track, I'm looking forward to see more when-based branching in writeValue that will handle the different value types. The code will be quite similar to what is being done for Json here:
https://github.com/status-im/nim-json-serialization/blob/master/json_serialization/writer.nim#L178-L204

The next step would be to implement the TextBlocks format as well and to handle the exception types in a special way as the original description in #72 suggests.

chronicles/textlineserializer.nim Outdated Show resolved Hide resolved
chronicles/textlineserializer.nim Outdated Show resolved Hide resolved
chronicles/textlineserializer.nim Outdated Show resolved Hide resolved
chronicles/textlineserializer.nim Outdated Show resolved Hide resolved
chronicles/textlineserializer.nim Outdated Show resolved Hide resolved
w.stream.writeText ": "

proc writeValue*(w: var TextBlockWriter, value: auto) =
w.stream.writeText value
Copy link
Contributor

@zah zah May 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need code here that will call the right write routine. For example:

when value is array:
  writeIterable(w, value)
elif value is object:
  w.stream.write '{'
  enumInstanceSerializedFields(value, fieldName, filed):
    writeField(w, fieldName, field)
  w.stream.write '}'
else ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now made changes of that nature in both textBlock and textLine.

Since this changes the output of textBlock, I went ahead and enabled growing tabs recursively for objects within objects within object etc.

@@ -72,6 +73,13 @@ type
colors: static[ColorScheme]] = object
output*: Output

TextBlockBRecord*[Output;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can drop all Record types in favour of a single generic Record type. It will have a Format parameter that will be either Json, TextBlockLog or TextLineLog.

From the Format parameter, you can get the writer type with WriterType(Format)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting a generic Record was fairly straightforward, but a generic Writer was been difficult since I'd want inheritance-like behavior. See question in PR thread.

@JohnAD
Copy link
Author

JohnAD commented May 20, 2020

Do you know of a way in which I can do something like:

type
  A[x: static[int]] = object of RootObj
    blah: string

type
  B[x: static[int]] = object of A
    morestuff: string

proc say(r: B) =
  echo r.morestuff
     
type
  C[x: static[int]] = object of A
    otherstuff: string

proc say(r: C) =
  echo r.otherstuff
     
proc bing(foo: A) =
  when foo.x == 1:
    foo.say
  else:
    foo.say
    foo.say

var testB = B[1](morestuff: "left")
var testC = C[2](otherstuff: "right")

testB.bing()  # should print "left" once
testC.bing()  # should print "right" twice

I've tried various combinations to get a Nim to compile such a thing. I'm not even sure it is possible. Can a class with compile-time generics be inherited from?

@JohnAD
Copy link
Author

JohnAD commented May 20, 2020

Figured out the answer on myself. Put the answer on the forum just in case others find it useful:

https://forum.nim-lang.org/t/6359

timestamps: static[TimestampsScheme],
colors: static[ColorScheme]] = object
LogRecord*[Output;
logformat: static[LogFormat],
Copy link
Contributor

@zah zah May 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry my explanation wasn't clear enough. The names of the formats such as Json, TextBlock and TextLine are Nim type names. You don't need to (and you shouldn't) pass them as static parameters.

The correct definition is

type
  LogRecord[Output; Format; timestamps: static[TimestampsScheme], ...] = object
    output*: Output 
    writer*: WriterType(Format)

You can initialize the writer by passing a stream to its init function like it's done here:
https://github.com/status-im/nim-json-serialization/blob/master/json_serialization/writer.nim#L20-L26

I haven't tried the above and perhaps the use of WriterType is pushing Nim a bit too far. If that's the case, you can make the LogRecord parametric on a Writer type directly (instead of Format).

@zah
Copy link
Contributor

zah commented May 20, 2020

I don't think using inheritance is necessary here. From your example, I cannot see what is the direction you've tried to explore. You might want explain the plan in more detail or you can try to follow my suggestion above, which should get you to a working final design quite soon.

@JohnAD
Copy link
Author

JohnAD commented May 23, 2020

Attempted the writer field of generic type WriterType within the generic LogRecord type as I think you were showing. I wasn't so successful. I'll have to ask more questions tomorrow. I then tried a generic type within a generic type using inheritance from a WriterType type for each of the writers. This at least compiles, but I'm getting a run-time segfault on init.

Will try again tomorrow. 😄

@JohnAD
Copy link
Author

JohnAD commented May 25, 2020

Was updating the test code to make sure I'm not breaking something fundamental yet. And...

Support for customLogStream makes my approach fundamentally flawed. I wish I'd seen that sooner. I'll be taking a different approach in the next few commits.

In fact, you might see a new PR request if it is too radically different.

@zah
Copy link
Contributor

zah commented May 26, 2020

customLogStream can be discontinued once we get this working.

It suffers from a flaw that the serialization format approach will solve. Log statements from third party libraries won't use your customLogStream, so it's less practical than specifying a global log format.

@JohnAD
Copy link
Author

JohnAD commented May 31, 2020

Just FYI, I'll be able to get back on this project on June 4th.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants