I really wish I'd thought of this method when I was building a search based application. It was my first time and I struggled with structuring everything
What I find so interesting is that we all effectively do TDD, except without commitment to it - Imagine writing some code and not at least testing it out with several test cases.
The absolute bare minimum should be for you to write those informal tests down and commit them to the repo.
That's some golden knowledge I've gotten over time
It just requires the overhead of setting up the test runner
But the orthodoxy seems to be write the tests first, see them fail, then write code, not write a little bit of code, write some test cases, repeat. How "test first, then code" works in a compiled language like C++ or Rust be beyond me (unless I'm taking this to a literal conclusion).
> How "test first, then code" works in a compiled language like C++ or Rust be beyond me
It's not really any different than in dynamic/interpreted/weakly-typed languages. "Writing the test" for a function sometimes just includes writing a method/function with the appropriate type signature that does nothing (maybe returns a dummy value).
Forcing you to view the code you're implementing from the viewpoint of someone calling that code from the very beginning is one of the advantages/goals of TDD. If you find that it's difficult to set up the objects/data you need to write a test, eg, your code has a bunch of implicit dependencies on other components being in a particular state or it takes a ton of arguments that all have to be constructed, that's usually a strong indicator that you should rethink the design. You're getting early feedback on your API design before you waste time implementing it.
Say I'm building a logging library, is there any sort of generally agreed-upon standard per what a log file should look like?
I know there's several formats that lnav supports, but I'm not familiar with them.
I've always had trouble before figuring out what a good compromise between log format and flexibility looks like. Especially wrt newlines in the log message itself (eg if I want to log a stack trace)
Any thoughts for a format that would generally work ootb in lnav or other log viewers?
Not sure about lnav but most log aggregation systems support json and logfmt-formatted logs, and there are many standard logging libraries that supports emitting those formats
Of those json is better if you want to be able to do more advanced stuff (nest dictionaries, use lists, ...) and logfmt is better if you want to have human-readable logs without external tools as well, an example line can look like
Agree with logfmt. I wrote the logfmter python library: https://github.com/jteppinette/python-logfmter. You can quickly have all of your logs (including 3rd party) converted to this style.
Thank you!
Now when you say json logging, are there any common patterns you can guide me to look at? Just looking around for JSON logging gives me results like [1] which talk about JSONL (object per line, presumably JSON serializer makes sure to not emit literal newlines).
But some other places describe this a bit more liberally. And [2] notes that I should include a time stamp in each log entry which makes sense.
In general if you use things like filebeat or promtail to do log ingestion into centralized log search systems (elasticsearch or loki in these examples) they prefer one object per line.
It makes parsing and keeping track of the "state" of the file a lot easier. Say that your application crashes/gets killed halfway through writing a log message / json dict and then gets restarted and appends to the log file. How should the log reader handle that case if it suddenly becomes a valid nested object? And even if it doesn't, should it throw away the first new log message as well because that was embedded in the invalid json object? Much easier to just say "one line is one json object, if there are literal newlines that's the delimeter to start a new parse".
And yes in any case it's good to have a timestamp on your log message no matter the format, unless you're logging somewhere you know that it gets added immediately (like the systemd journal). Your log parser/forwarder can add a timestamp for when it reads your log message but that is not necessarily the same as when your application emits it.
and not put any variables into the msg key (and not really do advanced formatting for any of the keys for that matter). This way once you get it put into a log system that understands your format you can do searches like "all log messages where user=foo" or "all statuses that are >=500 and <600" or search on specific messages, all without having to craft elaborate regular expressions and with better performance since the log search system can do indexing and various optimizations so that it doesn't have to be a full-text search every time.
lnav does support JSON-lines and logfmt logs. For JSON-lines, it will pretty-print the log messages to make them human readable.
For logfmt, I seem to remember the spec not being very clear on quoting semantics (maybe I'm wrong). Anyhow, I would suggest using JSON since it has pretty broad support at this point.
You would know what is supported what with you being the author, just saying that the docs aren't super clear from a quick glance :).
And yes, I second the suggestion to focus on JSON. The main benefit of logfmt is that it's simpler for a human to parse directly but in general you probably shouldn't aim for that so..
There is a bunch of them (log formats). I don't think any is like ISO/ANSI standarized, but many tools work with many of the different formats.
Probably the most common one (or at least was most common, maybe not anymore) would be "NCSA Common log format" (or just CLF) which looks something like this:
127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
Many tools for getting analytics out of server-side logs can work with CLF and the various variations. But probably today there are more "modern" formats as well.
They did mention it. They use it for some of their older games but it seems like Ruffle isn't yet feature-complete with Action Script 3 and thus cannot be used to run their newer games
While Ruffle's AS3 support is still lacking a lot of features, since a couple months ago it's been able to play some simple games that require it. The build used on author's site is from 2021, and I just checked that the latest build is able to play several more AS3 games hosted there.
That's great news! I've been meaning to write a cron script or something to fetch the latest Ruffle every week or so, so thanks for reminding me to do that. Thanks also for your work on Ruffle, it's really great.
I'm waiting for it to develop further, I'm very excited, especially because I still play Crystal Saga everyday, I don't know why, but it's got something that I haven't been able to find in any other games.
But sadly, I haven't been able to make Crystal Saga work using Ruffle
MMOs are pretty much the last game Ruffle or any in-browser emulator will get to support - not just because it's likely some of the most complex piece of code you can find, but also because MMOs are likely to use sockets, which AFAIK can't really be accessed in modern browsers at all.
It sounds like adding those features to ruffle would have been three order of magnitudes easier than writing a flash player from scratch
I understand contributing to OSS is a pain (I often end up with half implemented features in my own branch and never manage to merge them upstream) but he could have saved himself some trouble.
It seems to me like a very different skillset required to reimplement a runtime like the SWF player vs hacking together an alternative FLA compiler that's just good enough to work on your own games.
Ruffle still doesn't support Actionscript 3.0, I suspect the task is not that straightforward.
Closest equivalent that I can think of is the change-class function in CL.
That one also happens to be generic so you can control the finer details of what it means to change A to B