swiftloggingmetaprogrammingsourcekit

Capturing local variables in Swift log lines with minimal effort & maintenance


I’m trying to add local variable values/names to my Swift log lines. Out-of-the-box Swift provides a great way to adorn log lines with #file, #function etc without explicit effort. I want to go further and scoop up all the local variables in scope at the log site too.

log(
    message: "Things went sideways", 
    // I want to log the following dictionary of local variables without 
    // having to write, maintain or even see the dictionary
    locals: ["foo": foo, "bar": bar, "baz": baz, "buz": buz] 
)

Putting aside whether it’s a good idea or not (performance, security, privacy, thread-safety etc), what’s the best way to automate the passing the of the local variable dictionary to the log function? I already have a Mirror-based solution to encode them once captured. It seems my options are:

  1. Propose the Swift team add a #localVars special literal
    Seems unlikely, they have a lot on their plate already, plus I may be the only person who wants it
  2. Fork Swift and implement my own #localVars special literal
    Keeping up with changes to Swift would probably be more work than manually adding dictionaries of local variables to my log lines
  3. Wait for Swift compiler plugins to become a thing
    Could be a long time, forever perhaps
  4. Build a SourceKit-based tool to inject local var maps before compilation
    Probably the most feasible option, but has its challenges. How do I edit the pre-transform versions but get Xcode to compile the post-transform versions? Can I just transform the files I've edited since last transformation? Does Xcode index the pre or post transformation version of my files?
  5. Continue manually
    Write (and maintain and wade through) annoying dictionaries of local variables in thousands of log lines. Ugh
  6. Forget the whole idea
    That would be a pity. Having locals in my incident logs (even just when running in development) makes those logs far easier to understand

I'm really hoping someone has a brilliant suggestion as the above options all seem uninspiring


Solution

  • I'm not really sure that this question fits the SO purpose. It's about programming, yes, but it's about sort of well known state (you can't do this in Swift), covers lot of topics, will lead to an opinionated answers what you should do, ...

    I'm not looking for the bounty, but it's hard to write meaningful & short comments, so here's the "answer".


    Propose the Swift team add a #localVars special literal

    Seems unlikely, they have a lot on their plate already, plus I may be the only person who wants it

    You don't know if you're the only person who wants it unless you move this kind of question/discussion to:

    I'm not sure how many Swift engineers are on SO. Saw couple of them, but these two places I mentioned are a better place for this question for sure.


    Fork Swift and implement my own #localVars special literal

    Keeping up with changes to Swift would probably be more work than manually adding dictionaries of local variables to my log lines

    As you said, I expect that it's way more work than constructing these dictionaries manually.


    Wait for Swift compiler plugins to become a thing

    Could be a long time, forever perhaps

    Never, probably, don't know. Here's the Ted response:

    I think being able to facilitate tooling that integrates more closely with the Swift compiler would possibly be a great addition to the project, if it can be done well. The main concerns I have are stability of the plugin interface and security.

    &

    None of this has a design, but there is a lot of great stuff that could be built here. If you are interested in exploring this more, I think a natural point would be to suss out technology directions here first on swift-dev. A swift-evolution proposal seems like a natural product of a lot of discussion and design, but I'd expect the discussion for that kind of extension to Swift to probably happen more on swift-devs than swift-evolution since it is about the internals of the compiler and tools, rather than the language.


    Build a SourceKit-based tool to inject local var maps before compilation

    Probably the most feasible option, but has its challenges. How do I edit the pre-transform versions but get Xcode to compile the post-transform versions? Can I just transform the files I've edited since last transformation? Does Xcode index the pre or post transformation version of my files?

    You'll face lot of issues with Xcode. For example - I tried to integrate Swift formatter into my build process and gave up. Xcode had a lot of issues with modified Swift files. Like - you edit the file, hit build, Swift formatter reformats, Xcode build it, you try to edit the file again and dialog appears that the file was modified with a question if you'd like to reload it, ... I also tried to tell the Xcode to Save All before the build starts, didn't work. It sometimes worked, sometimes not.

    Is this feasible? Maybe. I ended up reporting it to Apple, but no feedback/fix yet. Just one example of what you'll be facing if you decide to go this way.


    Continue manually

    Write (and maintain and wade through) annoying dictionaries of local variables in thousands of log lines. Ugh

    Here's the question - one should compare how much work it is. Are you able to modify Swift compiler in this way that it takes less time than the overall time of this manual job? What about future? Are you willing to spend time on merging changes and constant updates? Especially when internals can be changed?

    As I'd like to automate lot of things as well, I always ask myself - is it worth it?


    Forget the whole idea

    That would be a pity. Having locals in my incident logs (even just when running in development) makes those logs far easier to understand

    Do you really need all locals in logs? Is it a good idea? I don't know context of your case or why did you started thinking about this, but I'm not a big fan of polluted logs.

    We have a debugger, we can set break points, break points that execute expressions and then automatically continue, you can store them within a project, you have access to frame variable, ...

    You wrote - even just when running in development - why not to leverage tools we already have? Like mentioned breakpoints for example. Did you consider the security/privacy aspect? When you skip this condition (development only), it will become production as well and this is not a good idea at all. Why do you think Apple is redacting data in logs (see Formatting Log Messages)?

    The main purpose of these questions is - do you really need this? Is there any other way? Is this a even good idea?