The Go programming language, also known as Golang, has gained popularity among software practitioners since its release in 2009. This language offers various features and advantages that make it a preferred choice for many developers. Golang is an awesome language, but it has sanctioned our country. It is similar to C programming language.
We can use it for writing code as terminal applications or servers. I had experience in using it for writing ReST API and GrapQL servers. For the terminal application there are many fun library out there like bubbletea
and tcell
which provide easy-to-use interfaces for creating interactive command-line applications.
In Go 1.16, module-aware commands report an error after discovering a problem in go.mod
or go.sum
instead of attempting to fix the problem automatically.
In most cases, the error message recommends a command to fix the problem.
One useful tool that comes with Golang is gotip
, which allows you to test upcoming changes and experimental features.
go install golang.org/dl/gotip@latest
gotip download
After installation, use the gotip
command instead of your normal go command to have latest features.
To update, run gotip download
again. This will always download the main branch.
To download an alternative branch, run gotip download BRANCH
and to download a specific CL, run gotip download NUMBER
.
You can control to use cgo
with CGO_ENABLED
flag in go build.
We have different implementation of C standard library.
To test with go, testify is an awesome library. It has suite, require and assert.
Always use _test
prefix on packages for writing tests but in case of internal tests
in which you need to access private package members use _internal_test.go
as filename.
// Define the suite, and absorb the built-in basic suite
// functionality from testify - including a T() method which
// returns the current testing context
type ExampleTestSuite struct {
suite.Suite
VariableThatShouldStartAtFive int
}
// Make sure that VariableThatShouldStartAtFive is set to five
// before each test
func (suite *ExampleTestSuite) SetupTest() {
suite.VariableThatShouldStartAtFive = 5
}
// All methods that begin with "Test" are run as tests within a
// suite.
func (suite *ExampleTestSuite) TestExample() {
assert.Equal(suite.T(), 5, suite.VariableThatShouldStartAtFive)
suite.Equal(5, suite.VariableThatShouldStartAtFive)
}
// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestExampleTestSuite(t *testing.T) {
suite.Run(t, new(ExampleTestSuite))
}
// SetupAllSuite has a SetupSuite method, which will run before the
// tests in the suite are run.
type SetupAllSuite interface {
SetupSuite()
}
// SetupTestSuite has a SetupTest method, which will run before each
// test in the suite.
type SetupTestSuite interface {
SetupTest()
}
// TearDownAllSuite has a TearDownSuite method, which will run after
// all the tests in the suite have been run.
type TearDownAllSuite interface {
TearDownSuite()
}
// TearDownTestSuite has a TearDownTest method, which will run after
// each test in the suite.
type TearDownTestSuite interface {
TearDownTest()
}
// BeforeTest has a function to be executed right before the test
// starts and receives the suite and test names as input
type BeforeTest interface {
BeforeTest(suiteName, testName string)
}
// AfterTest has a function to be executed right after the test
// finishes and receives the suite and test names as input
type AfterTest interface {
AfterTest(suiteName, testName string)
}
// WithStats implements HandleStats, a function that will be executed
// when a test suite is finished. The stats contain information about
// the execution of that suite and its tests.
type WithStats interface {
HandleStats(suiteName string, stats *SuiteInformation)
}
Writing tests with testify
is awesome, so use them. Also, I write tests with mock for the higher modules and tests the low level one with the real dependencies.
For application that has really great mocks like redis
, I have used them instead of real one.
As I said there are mainly two types of applications developed by Golang. In the terminal applications, it is better to use pterm to show the logs and other information instead of simply printing them. In case of the server applications, zap is a better choice because it has structure logging, and you can also write the logs on console and syslog at the same time.
Structure logging increase the search efficiency for when you want to search among your logs on your log aggregation system.
The current status of the major functional components for OpenTelemetry Go is as follows:
Tracing | Metrics | Logging |
---|---|---|
Stable | Stable | Not Yet Implemented |
With this release we are introducing a split in module versions. The tracing API and SDK are entering the v1.0.0 Release Candidate phase with v1.0.0-RC1 while the experimental metrics API and SDK continue with v0.x releases at v0.21.0. Modules at major version 1 or greater will not depend on modules with major version 0.
The SDK requires an exporter to be created. Exporters are packages that allow telemetry data to be emitted somewhere - either to the console (which is what we’re doing here), or to a remote system or collector for further analysis and/or enrichment. OpenTelemetry supports a variety of exporters through its ecosystem including popular open source tools like Jaeger, Zipkin, and Prometheus.
import stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
func main() {
exporter, err := stdout.New(
stdout.WithPrettyPrint(),
)
if err != nil {
log.Fatalf("failed to initialize stdout export pipeline: %v", err)
}
}
Exporter depend on the task and the service for example the Jaeger exporter is in the following package:
import "go.opentelemetry.io/otel/exporters/jaeger"
This block of code will create a new batch span processor, a type of span processor that batches up multiple spans over a period of time, that writes to the exporter we created in the previous step.
ctx := context.Background()
bsp := sdktrace.NewBatchSpanProcessor(exporter)
s := sdktrace.AlwaysSampler()
tp := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(bsp), sdktrace.WithSampler(s))
// Handle this error in a sensible manner where possible
defer func() { _ = tp.Shutdown(ctx) }()
OpenTelemetry requires a trace provider to be initialized in order to generate traces. A trace provider can have multiple span processors, which are components that allow for span data to be modified or exported after it’s created.
First, we’re asking the global trace provider for an instance of a tracer, which is the object that manages spans for our service.
tracer := otel.Tracer("ex.com/basic")
ctx = baggage.ContextWithValues(ctx,
fooKey.String("foo1"),
barKey.String("bar1"),
)
func(ctx context.Context) {
var span trace.Span
ctx, span = tracer.Start(ctx, "operation")
defer span.End()
span.AddEvent("Nice operation!", trace.WithAttributes(attribute.Int("bogons", 100)))
span.SetAttributes(anotherKey.String("yes"))
meter.RecordBatch(
// Note: call-site variables added as context Entries:
baggage.ContextWithValues(ctx, anotherKey.String("xyz")),
commonAttributes,
valueRecorder.Measurement(2.0),
)
func(ctx context.Context) {
var span trace.Span
ctx, span = tracer.Start(ctx, "Sub operation...")
defer span.End()
span.SetAttributes(lemonsKey.String("five"))
span.AddEvent("Sub span event")
boundRecorder.Record(ctx, 1.3)
}(ctx)
}(ctx)
There are tracers for internals of go libraries available at opentelemetry-go-contrib with experimental version v0.21.0:
There is an official library for AMQP in Golang:
An AMQP 0-9-1 Go client maintained by the RabbitMQ team
Also, there is another official library for Streams in Golang:
A client library for RabbitMQ streams
Creates arrays and slices. It tries to demo some features of Go in Array.
Hello world example in beehive.
Type switch and Interface cast example.
How do closures work with upper scope variables?
Introduction to go conditional variables.
Go Defer Here and Now!
Says back everything you say to it.
Fibonacci sequence in Go.
Adds some C to Go. 😋
Monte-Carlo method for estimating the PI. check here for more information.
Go uses zero initiation but sometimes you want some initiation and you want it lazy ...
Let's use redis as a cache with MessagePack coding
In the Memory of Roya Taheri.
The reader-writer-problem in Go.