Hacker Newsnew | past | comments | ask | show | jobs | submit | aleksi's commentslogin

You can make it run much better by increasing the game's process priority with `renice`. I know that sounds like something that should not work, but it does.


> If you have a struct with a simple int field, and you store that somewhere as an *int, the entire struct and anything it points to will be kept alive.

While Go allows interior pointers, I don't think what you say is true. runtime.KeepAlive was added exactly to prevent GC from collecting the struct when only a field pointer is stored. Take a look at this blog post, for example: https://victoriametrics.com/blog/go-runtime-finalizer-keepal...


I don’t believe that’s the case based on the example in the blog post. The fd field in that struct was passed into the later function by value (i.e. as an int, not an *int), so there was no interior pointer in play at all.


You are right; I stand corrected


1) The idea is that your library should accept the slog logger and use it. The caller would create a logger with a handler that defines how log messages are handled. But there are problems with supported types; see my other comments.

2) It is improved in 1.25. See https://github.com/golang/go/issues/59928 and https://pkg.go.dev/testing#T.Output. Now it is possible to update slogt to provide correct callsite – the stack depth should be the same.


1) Right, but this is complicated and annoying. Imagine a world where you could just pass your existing logger in, because my library references an interface like `stdlib/logging.GenericLoggerInterface` and slog, zap, zerolog, etc. all implement that! Would be nice!

2) TIL about `T.Output`, thank you, that's great to know about. Still annoying and would be nice if the slog package showed an example of logging from tests with correct callsites. Golang gets so many things right about testing, so the fact that logging in tests is difficult really stands out and bothers me.


But that is exactly what slog provides? The a unified interface that can be implemented by other logger libraries. Yes the Logger itself is not the interface, but the Handler it is backed by is.


My biggest gripe with slog is that there is no clear guidance on supported types of attributes.

One could argue that supported types are the ones provided by Attr "construct" functions (like slog.String, slog.Duration, etc), but it is not enough. For example, there is no function for int32 – does it mean it is not supported? Then there is slog.Any and some support in some handlers for error and fmt.Stringer interfaces. The end result is a bit of a mess.


All values are supported.


Well, is fmt.Stringer supported? The result might surprise you:

  req := expvar.NewInt("requests")
  req.Add(1)
  
  attr := slog.Any("requests", req)
  
  slog.New(slog.NewTextHandler(os.Stderr, nil)).Info("text", attr)
  slog.New(slog.NewJSONHandler(os.Stderr, nil)).Info("json", attr)
This code produces

  time=2025-09-12T13:15:42.125+02:00 level=INFO msg=text requests=1
  {"time":"2025-09-12T13:15:42.125555+02:00","level":"INFO","msg":"json","requests":{}}
So the code that uses slog but does not know what handler will be used can't rely on it lazily calling the `String() string` method: half of the standard handlers do that, half don't.


If you need more control, you can create a wrapper type that implements `slog.LogValuer`

    type StringerValue struct {
        fmt.Stringer
    }

    func (v StringerValue) LogValue() slog.Value {
        return slog.StringValue(v.String())
    }

Usage example:

    slog.Any("requests", StringerValue{req})

There might be a case for making the expvar types implement `slog.LogValuer` directly.


So clearly not all values are supported.

And I know that I can create a wrapper for unsupported types. My problem is exactly that – I don't know what types are supported. Is error supported, for example? Should I create a wrapper for it? And, as a handler author, should I support it directly or not?


Not sure what your definition of "supported" is, but I'm afraid you're going to have to bite the bullet and ... gasp ... read the documentation https://pkg.go.dev/log/slog


Not sure I understand your sarcasm. I read the documentation, source code, handler writing guide, and issues in the Go repository multiple times over two years, and I use slog extensively. Go is my primary language since r60. I think I know how to read Go docs.

Now, please point me to the place in the documentation that says if I can or can't use a value implementing the error interface as an attribute value, and will the handler or something else would call the `Error() string` method.

My definition of "supported" is simple – I could pass a supported value to the logger and get a reasonable representation from any handler. In my example, the JSON handler does not provide it for the fmt.Stringer.


https://pkg.go.dev/log/slog#JSONHandler.Handle

> Values are formatted as with an encoding/json.Encoder with SetEscapeHTML(false), with two exceptions.

> First, an Attr whose Value is of type error is formatted as a string, by calling its Error method. Only errors in Attrs receive this special treatment, not errors embedded in structs, slices, maps or other data structures that are processed by the encoding/json package.

So the json handler more or less works as if you called json.Marshal, which sounds pretty reasonable.


I think you missed the “any handler” part. Currently, the types that my library package could use depend on the handler used by the caller. This limits types to an unspecified subset, making things quite impractical.


any handler is too broad, maybe my custom handler only logs strings and ignores ints.

for a reasonable substitute subset, use the core language types, and implement LogValuer for anything complex.


That seems to work as expected?

The output of data is handled by the handler. Such behaviour is clearly outlined in the documentation by the JSONHandler. I wouldn't expect a JSONHandler to use Stringer. I'd expect it to use the existing JSON interfaces, which it does.

I'd expect the Text handler to use TextMarshaller. Which it does. Or Stringer, which it does implicitly via fmt.Sprintf.


My problem with that is that it makes it impossible to use slog logger safely without knowing what handler is being used. Which kind of defeats the purpose of defining the common structured logging interface.


> Which kind of defeats the purpose of defining the common structured logging interface.

Does it, though? Why would the log producer care about how the log entires are formatted? Only the log consumer cares about that.


As a producer of the response, if I didn't care about being understood, I would use a made-up language. As a consumer, you may care about understanding my response, but you cannot do anything about it.


Hence the design. The producer coming up with a made up language that makes sense to the producer, but probably doesn't make sense to the consumer — especially when you have many different consumers with very different needs — is far more problematic than the producer providing an abstract representation and allowing the consumer to dig into the specific details it wants.

As with everything in life, there are tradeoffs to that approach, of course, and it might be hard to grasp if you come from languages which different idioms that prioritize producer over consumer, but if you look closely everything about Go is designed to prioritize the needs of the consumer over the needs of the producer. That does seem to confuse a lot of people, interestingly. I expect because it isn't idiomatic to prioritize the consumer in a lot of other languages and people get caught up in trying to write code in those other languages using Go syntax instead of actually learning Go.


[flagged]


A good, if a bit strange, example. A CPI logger wouldn't need to log the same thing as an access logger, but the producer need not care about who is consuming the logs. Consumers might even want to see both and, given the design, can have both.


[flagged]


Certainly logs lose their value if they are wrong. And either approach is ripe for getting things wrong. But the idea is that the consumer is more in tune with getting what the consumer needs right. The producer's assumptions are most likely to be wrong, fundamentally, not having the full picture of what is needed. What is the counter suggestion?


[flagged]


We've banned this account for continually posting unsubtantive comments and ignoring our previous request to observe the guidelines.

If you don't want to be banned, you're welcome to email hn@ycombinator.com and give us reason to believe that you'll follow the rules in the future. They're here: https://news.ycombinator.com/newsguidelines.html.




I open-sourced my MongoDB alternative, and all I got was this lousy lawsuit.


> It's too slow to run in prod to be worth it

I disagree there. It is reasonable to run a few service instances with a race detector. I have a few services where _all_ instances are running with it just fine.


See https://manticoresearch.com/comparison/vs-sphinx/. Sphinx is no longer open-source.


> Tigris means tiger

I'm pretty sure Tigris Data is named after the Tigris river (https://en.wikipedia.org/wiki/Tigris), and the name does not mean "tiger".


In French, the river and the animal are both "tigre"


You'd be surprised. Tigris is the latinized version of the name of the river in ancient Greek (τίγρης) which also means tiger in ancient Greek.

The common underlying etymology is an even older into-european term translated roughly as "sharp" or "pointy" (in the case of the tiger I guess referring to the teeth).

From a biblical etymology page:

The name Tigris shares its root with the word "tiger" (more precise: the word "tiger" and the name Tigris are identical in Greek). That means that in deep antiquity the tiger and the Tigris had signature qualities that were comparable and from which both derived their name. The word tiger and the identical name Tigris both come from the Avestan word tighri, which means arrow, or the more general tigra, which means sharp or pointed.


Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: