Hacker News new | comments | show | ask | jobs | submit login
Show HN: A simple Go web server with logging, tracing, health check (gist.github.com)
318 points by enricofoltran 6 months ago | hide | past | web | favorite | 91 comments




I went ahead and started fleshing out a combination of both of these along with an example of using golang templates: https://github.com/Xeoncross/vanilla-go-server


Love this type of thread and great find on the cert stuff. Super cool


This reminds me of an ongoing discussion I was having with friends about Golang web frameworks -- one side of the argument is that you can achieve so much with the standard library that frameworks are "unnecessary", but folk like me want an ORM(ish) layer and some kind of back-office scaffolding.

https://beego.me and https://iris-go.com are nice, but we (all) have (as yet) to find a Django-like framework that comes with an extensible back-office.

So... Any pointers on the latter? I can do an Ask HN, but this seems like a good context to ask in.

(Edited to add: why the downvotes? Is this not a legitimate question?)


Rather than use a full-fledged framework, I would recommend combining orthogonal packages such as

- julienschmidt/httprouter [1] for routing,

- jmoiron/sqlx [2] for SQL access, and

- gorilla/websocket [3] for websockets

sqlx isn't an ORM; it's more a convenience wrapper around the standard library's database/sql package.

gorm is the nicest ORM I've found, but I think even the well-written ORM packages are unnatural to use because of restrictions in Go's type system.

(Sorry if this isn't the kind of answer you were hoping for.)

[1] https://github.com/julienschmidt/httprouter

[2] https://github.com/jmoiron/sqlx

[3] https://github.com/gorilla/websocket


Iris is a poorly maintained project that I would not recommend for production use.

See the drama unfold at https://www.reddit.com/r/golang/comments/57w79c/why_you_real... and https://www.reddit.com/r/golang/comments/57tmp1/why_you_shou...


This is totally propaganda, they spamm those links without even reading the code. Florin is clearly putting lies to a part of the community to deflame the Iris via the slack golang chat. He's also banned the author of the web framework without notice or any other action from his behalf. Is this a healthy relation between an author of a popular software and a guy who never wrote a single line of code?


Well, it _seemed_ nice. Regardless, I'm a bit more concerned with back-office scaffoldings myself. Any pointers?


I wrote a scaffold generator here you may find interesting.

https://github.com/fragmenta/fragmenta

It’s fairly simple to write some simple generator using the built in text/template package if all you want are admin scaffolds.


Note the dates and you'll see the truth, if you're a programmer you can also read the code, Iris doesn't even use the libraries the 1+ year old article claims to be used there.


I regularly go down this road with go. My conclusion is that it's never going to suit that use case. I'm not even sure it's not technically doable (i think introspection and interface{} can go quite far), but it's just culturally opposed to this kind of project.

People like go for its minimalist approach. Not in the sense that you don't have a lot of code to write, but more in the sense that you are in control of everything that happens, and that you can read an understand every part of your codebase.

ORMs , code gen, magic wrappers, etc is something that people in that community just hate.


> ORMs , code gen, magic wrappers, etc is something that people in that community just hate

Mostly agree except for code-gen --- definitely not so in the real world! I'd say most Gophers on the whole at a minimum don't mind it, and many either outright ---or eventually--- embrace it.

Depends on the nature and purpose(s) of the Go code-base but for many, it's as natural and idiomatic as is the extensive use of the macro preprocessor for many-perhaps-most grown, matured, "non-trivial" C code-bases. (Just fewer pitfalls in exchange for a bit more set-up effort.)


I’m the same way - I have lots of side project ideas I’d love to use Go for but get that early Rails like productivity. I maintain a few Rails apps and now view many of the things I’ve done as hacks to work around the lack of concurrency (though that was just Rails’ reality in late 2000s).

Elixir is close to my ideal though I like static types and a better community around libs would be nice.


You might be interested to check out https://gobuffalo.io/


I understand that, which is why I said "ORM(ish)". But a back-office scaffolding would go a long way to move some of us off of Django.


Why do you want to move off of Django?


Because we're all using Go for other projects (even if piecemeal) and would like to build the entire project in a single language.


i personaly only would use go for very technical, low-level middlewares (as in, just above the OS layer) involving networks.

The good side to it being simple to understand and maintain is that you won't pay a lot of debt if you're adding it to your stack.

There isn't a single language that fits all use case perfectly anyway, so we'd have to just go to the "best tool for the job" approach in the meantime.


> i personaly only would use go for very technical, low-level middlewares.

Care to extend upon why you don't feel go is a good fit for other programming?


I'd argue that what you probably want in a new project (possibly with legacy db), is a graphql wrapper for your db, and a single-page js app (react/vue/elm/etc.) front-end.

Which means the server side would need a way to wrap the db for graphql (along with a way to set up authorization), and the front-end would need to be able to discover/generate the crud parts.

If you really want a "legacy"/"traditional" framework (fat appserver handling form input, rendering html, talking to db backend), I think the mature ones will be hard to beat (eg: django).



And the rest of Marks (and others) buffalo https://gobuffalo.io/


I really like Goa: https://github.com/goadesign/goa - it has integration with Gorm via Gorma: https://github.com/goadesign/gorma


Here's a quick attempt at the same thing in Java (although note that the command line format is different):

https://gist.github.com/tomwhoiscontrary/b4888b86057c74a636c...

The main takeaway is that the JDK's built-in web server is poor:

* There is no way to configure timeouts

* Filters have to be added to each handler separately, by mucking with its filter list

* Filters have to extend an abstract class with two methods (one totally pointless), so you can't use lambdas for them

* Handlers use a simple string prefix match, so a request for "/healthzone" will hit the health handler

* The stop method always blocks for the specified timeout, and never returns early as the docs promise (IME)

Other minor irritations:

* There is no method to parse an InetSocketAddress from a string

* Java's support for handling clean process shutdown is not great; i think there's some sort of race between the shutdown hook and the logging system getting shut down, so you never see the "Server stopped" message


If you're using java, just use finagle's http server and be done with it. It is really good and runs most all of twitter.com's production web services. The very definition of "web scale":

https://twitter.github.io/finagle/guide/Quickstart.html


"zero dependencies" was an essential feature of this. Finagle would be a dependency. And, according to a quick 'gradle distZip', it drags in a further 49 transitive dependencies.


That seems sensible. Really cool project (and I didn't mean to piss on it), just wanted to point out that generally speaking, finagle is serious business and can be used already.


Not sure if I would use Twitter as a success story for handling scale. Not exactly the poster boy of reliable software.


You're kidding, right? After they ditched ruby and wrote finagle, they've been super reliable. They've got one of the biggest Apache Mesos clusters in the world (second only to Apple's Siri backend per Apple employees who presented at MesosCon) and run it all with Apache Aurora, a really nice mesos framework for long running jobs.

Twitter, Soundcloud, Salesforce, Pinterest, FitBit, Tumblr, Box, Foursquare... What do they all have in common? They all run finagle in production. For java, it is about as battletested and as good as you'll get unless you want to write your own. Personally, I'm more of a golang and python developer, but respect where it is due. Twitter is massively more scalable than the overwhelmingly majority of the sites on the internet and they've gotten their act together since abandoning Ruby and the fail whale.


Is it Java or Scala? I only see Scala on this page: https://twitter.github.io/finagle/guide/Quickstart.html#a-mi...


Finagle proper is written in Scala, but you can use java as well for building services with it:

https://github.com/jghoman/finagle-java-example


Really good; web scale; reliable.

Pick two.


Yea, the built-in JDK HTTP server is pretty poor, but I don't think I've ever run across it in the wild thankfully.

> There is no way to configure timeouts

They're configured by properties if I recall.

> Filters have to be added to each handler separately, by mucking with its filter list

I personally prefer the explicitness of this.

As for the rest... I think a lot of these issues stem from the fact it's an old, not particularly well-known API in the JDK.


Hi twic, thanks for sharing this! I love to see implementation in other languages. I'm particularly interested in Rust, it would be awesome if anyone can make a attempt! :)


That would be awesome, but note that Rust, due to it being a low-level language, doesn't really have a net/http equivalent in its standard library and therefore any implementation would be more of a representation of the 3rd party libraries used.


Jetty does everything, else Spring with tomcat. I don't see any reason to rely on JDK web server (which I've never seen anyone seriouosly use.


I've been developing in Java for around 20 years and I never knew the JDK included a web server. This must be the thing I learned today ;)


Nice. Does anyone have a server like this but with the addition of

* serving of files and directories

* LetsEncrypt certificates and SSL


static file server in go:

    package main

    import (
        "fmt"
        "net/http"
        "path/filepath"
    )

    var (
        host = "0.0.0.0"
        path = "/var/www/public"
        port = 8080
    )

    func main() {
        path, err := filepath.Abs(path)
        if err != nil {
            panic(err)
        }
        listenAt := fmt.Sprintf("%s:%v", host, port)
        fmt.Println("static-serve-dir serving", path, "over http at", listenAt)
        err = http.ListenAndServe(listenAt, http.FileServer(http.Dir(path)))
        if err != nil {
            panic(err)
        }
    }


The builtin golang.org/x/crypto/acme/autocert [0] package manages SSL for you easily through Lets Encrypt.

[0]: https://godoc.org/golang.org/x/crypto/acme/autocert


golang.org/x/ packages are not builtin. You still must download them and use them just as you do any other dependencies, they just share some contribution process and developers with golang's stdlib.


Just wrap the handlers with middleware rather than using that filter abstraction.

Same thing!


By 'middleware', do you mean another handler? That would work, but i'd still have to wrap each handler separately.


It's a nice reference program to show you what's going on.

I build stuff like this for a living. I'd recommend not re-inventing the wheel yourself and using a nice web framework, like Echo (https://github.com/labstack/echo) or Gin (https://github.com/gin-gonic/gin). I prefer Echo due to a cleaner, mockable design, but they're equivalent.

You can throw up that web server in 1/10 the code to do the same thing, and using built-in middleware is less work than writing your own.


I also build stuff like this for a living and I tend to avoid frameworks :)

I don't care for Gin. I'll take a look at Echo.


I tend to agree and I’d throw Chi in the mix. I like Chi quite a bit. Or, use the Gorilla components and middleware.


I also use Chi a lot and Chi and this example are actually complimentary: you can take the Chi router and pass it to an http.Server in the handler attribute to make it work.


Golang is self sufficient for a small scale web app.

It has HTML templates library, decent error handling, rpc, logging, built-in http server. Many people choose golang for that reason.


What do you mean by small scale? I think requests per second. Our Go-backed API has handled 90k rps without batting an eye. Or do you mean small scale as in team size? It is my understanding that Go was specifically designed to work for large organizations (cough Google cough).

Or do you mean single page JavaScript web sites? At which point Go would be the backing API? I don't see what qualifies Go for "small scale" vs "large scale."

Thanks for any clarification. Cheers!


I would say "small scale" would refer to project size in Go.


Thanks


Not akditer, but I think the key words are "self sufficient," i.e., the Go standard library provides a great deal of core functionality out of the box.

A larger project is more likely to require features provided by third-party packages.


A small scale means you won't use redis for in memory data storage. You will not need C++ to write heavy string processing and hash table lookup. Golang also doesn't scale well if you have some heavy processing involving trees(http://benchmarksgame.alioth.debian.org/u64q/binarytrees.htm...).


FWIW that benchmark is not reliable . Developers have submitted go programs that do far better, but they get rejected because they use custom memory allocators. This is despite the fact that C++ does precisely this with an arena allocator.

Go was not designed for the small scale, but the large:

- it has a sensible module system that makes compilation fast

- it's a simple language that encourages boring code - your coworkers will probably write code that works and that you can maintain

- Multithreading is a first class concept. Programs you build locally using typical patterns scale when you run them on massive multi-core servers

- the language is memory safe by default

C++ projects require experts to build, scale and maintain. Go is designed to give that capability to journeyman developers.

Yes C++ is generally going to be faster, but rarely do people talk about why that is. It usually comes down to: a smarter compiler, unsafe operations, or clever optimization. The first is legitimate, but rarely that significant. The second is a penalty that's usually worth keeping (you want bounds checking on arrays), and the third misses the point.

Sure the expert c++ developer could write faster code, but is that who you have? Are you going to take the time to do all that optimization work?


> Developers have submitted go programs that do far better, but they get rejected because they use custom memory allocators. This is despite the fact that C++ does precisely this with an arena allocator.

No, apr_pools.h was not custom written to make some programming language look better on a toy benchmark!

https://apr.apache.org/docs/apr/1.5/apr__pools_8h.html


Thanks for this. I have been writing toy golang servers for a while to try out various ideas and this really helps clarify some useful techniques and best practices.


This is likely better posted as a Show HN if it meets the guidelines:

https://news.ycombinator.com/showhn.html


Hi grzm, you are probably right. Can I do this myself? editing the title with a "Show HN" prefix is sufficient?


The ability to edit submissions is time-limited, IIRC. If you no longer see an edit link, you're likely outside of it. You can get in touch with the mods via the Contact link in the footer and they can update it for you. In my experience they're quite responsive.


So a hundred lines of pure boilerplate hooking up Go standard libraries, assumedly exactly how they were intended to be used. How is this news worthy?


Hi Ultimatt, this is just a reminder for me on how to do those things when I start a new app in Go, instead of always google for them. Didn't expect to hit the homepage!


as a go newbie, I find it helpful. it might not be for everyone.


Go is so hot right now


Yea lets ditch everything we learned about modularization in the past 20 years and put everything in one single binary


I don't think we did learn anything about modularization in the past 20 years. Programming languages still don't do it even remotely decently. Users still make a common mistake of splitting things into multiple files for the sake of splitting, just as your comment implies. These things are all about UX, which is known to be neglected in programming.


This is merely an example server with a router, middleware and two route handlers. This isn’t evangelism for monolithic application design, and there’s nothing inherent in Go that forces monolithic application design.


Having to rebuild thousands of binaries every time a vulnerability is found in a popular library is seriously hurting Linux distributions.

That, and having to handle vendorized dependencies.


> Having to rebuild thousands of binaries every time a vulnerability is found in a popular library is seriously hurting Linux distributions.

Do you have a source for this?


"Putting everything in one binary" is what we learned in the past 20 years. Most major languages either compile to a single artifact or they have some "bundling" trick to minimize runtime dependencies. Besides that, there are things like Docker which exist to solve the same problem.


Isn't Caddy written in Go? How is this different?


When you're writing a Go application and want just a few things out of a web server, something like this is a nice demonstration on how to do that with a few lines in your Go program. Yes, you could use Caddy, or you could even import it and use it as a library; but if you prefer something like this, there you have it.


I'm guessing this is a demonstration. Perhaps it's showing you all the things you can do with Go's in-process webserver library instead of an external webserver like Caddy?


I do not quite see the point of this (other than being an exercise).

We already have web server that do "logging, tracing, health check, graceful shutdown." I do not care about zero deps, because I only install them once and the deps are taken care of by the package manager.

In my opinion, the Go web server only makes sense as part of a Go application as a whole. But a standalone Go web server does not make much sense to me.


To do all of this in just over a hundred lines of code without having to import packages to do it is pretty incredible. It may be just an exercise but it is a very cool one.


I never said it is not a cool exercise. I meant more like it is not something one would download and compile and run it... like it is not a useful tool. Just a cool one. And that is fine.


Very few things on Hacker News are such that you can directly download and install them; I don't know why you'd have that expectation. Anything from a full app to a code snippet to a cool article that has nothing to do with tech is welcome here.


Hi chrisper, you are right! This is just a reminder for me on how to do those things when I start a new app in Go, instead of always google for them.


I like how you, as the owner of the repo and poster, agreed with me, yet I got -3 points...


FYI: You'll also get down voted for commenting on the down votes.

https://news.ycombinator.com/newsguidelines.html


I suspect you received down votes because your initial comment comes off as dismissive. A lot of HN members tend towards encouraging constructive criticism rather than only pointing out limitations (especially for Show HNs† which this effectively is) in the interest of facilitating a civil forum. Given the limitations of text (particularly online), it's easy to misinterpret tone. I think you could have said essentially the same thing with some simple rephrasing. For example:

> "I think this is likely a useful exercise. That said, I'm not sure I see myself actually using this."

> "We already have web server..."

Yeah, it's subtle, but I think it comes off differently as it's more upfront that doing this may actually have had a use. And both the writer and the reader are involved in the communication: you yourself can only control so much.

Anyway, this is only speculation.

https://news.ycombinator.com/showhn.html


Look at all the other gray comments here. Any comment questioning why this is so great appears to be severely triggering the masses.


Please don't break the HN guidelines by going on about voting in comments.

https://news.ycombinator.com/newsguidelines.html


I think this is more of a statement on how batteries beibg included in this language make it easy to build such things without a fuss.


I disagree, I will always prefer projects with the least dependencies given two options with the same feature set.

We should always try to strive to lower dependencies when it makes sense.


> We should always try to strive to lower dependencies when it makes sense.

Maybe, but I think 'when it makes sense', might be 'rarely'. There a 2 ways to avoid dependencies: 1. lean on a batteries-included standard lib as this gist does or 2. write it yourself.

Problem with 1. is standard lib libraries aren't always great, see 'where modules go to die' [1], (examples: httplib/urllib in Python, or the string libraries in PHP). This can stifle innovation and alternatives, unless an alternative with a strong marketing push can arise ('requests' for Python). Sadly, often because the situation isn't 'that bad' (as in the case of PHP) people continue to use poor APIs.

Problem with 2. is you're probably getting an order-of-magnitude fewer brain cycles on code you wrote yourself -- unless you can spend the extra effort to open-source it, and get lucky with popularity/contributors, it's likely to be inferior than a well-maintained 3rd party alternative.

[1] http://www.leancrew.com/all-this/2012/04/where-modules-go-to...


You spend brain cycles trying to navigate and integrate third party libraries, learning their APIs, keeping the dependencies updated.

I'd encourage developers, especially Nodejs devs, to look at their list of dependencies and ask the following two questions about each of them:

1. How long would it take me to replicate this functionality?

2. How often does this functionality need updating?

There is a threshold balanced between both of those questions where, once the numbers pass, it makes sense to bring in dependencies. But I truly believe the "instant gratification" primate part of our brains tends to overestimate the benefit of dependencies and underestimate the long term negatives of them.

Here's a common Nodejs example: Request. Request is used all over many projects. Did anyone who imports it even try to use http.request in the nodejs stdlib? Its actually pretty great. Now, you introduced a new dependency. You made your build process longer. You made your deploy artifact bigger. You've got to keep it up to date. You've got to make sure there aren't security breaches. You've got to learn a new API that, unlike the Nodejs stdlib, is just made by "some guy somewhere" and is horribly documented inside a Github README.

How long would it take me to replicate the functionality of request just using http.request? It depends what parts of request I'm using, but probably very little time. How often does this functionality change? Literally never. Literally never. HTTP/1.1 was finalized decades ago. Request, right now, has 48 open PRs, 560 open issues, was last "released" a couple months ago, and was fixing security issues which were definitely already fixed in stdlib.

But the primate part of your brain says "Eh fuck all that, I'll let future self deal with the negatives of a new dependency, what I want today is an API interface that's, like, 20% easier to use."


This is what I love about Go, and why I moved away from Node. The culture of fewer dependencies.

I only use the stldlib in Go, and a few packages (like google/uuid) that will become part of the stdlib at some point.

I know exactly what my program is doing, and why.

In Node, I would often hit 100+ dependencies before getting to the actual meat of the thing, and if there was a problem I had no idea where to look in the mess of other people's code. Given the number of PR's on the average node module, and the number of dependencies, I was guaranteed to be importing bugs every time I used an external module. Whether I hit one of those bugs and had to deal with it was a matter of luck. Dealing with bugs in someone else's library is a million times worse than writing the code myself.


If you are using Go to create something, then just use the built in webserver library (as shown in this repo). So that would make this project as a library (not just as an exercise / protoype) useless. Don't you think?


This project isn't a library though, it's a gist. Author says it's to remind them how to hook things up.


I assume this is showing you that you could easily build these things into your own application server. At least that's what I took away.


If I would use any code as a dependency in a project I am working on, I like it when the dependency I'm adding doesn't come with strings attached (extra deps) as things can get really weird really fast (using awesome bootstrap + icheck for instance)




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

Search: