This article will show you how to use the zerolog-sms logger, a logging library that allows you to send special log entries over SMS in your Go projects. We will also show how we added SMS capabilities through a custom Mobile logging level to the original zerolog, a popular logging library for Golang.

Sometimes, we want to be notified about a system’s status when something extraordinary happens, even if we are not close to a computer. The event could be some update on the progress of a long process or a terrible error that needs attention. For that, a sophisticated monitoring and alerting system like OpsGenie is usually employed. But you may need a simple way to get notifications on your phone without the hassle of configuring complicated tools. For that, you can integrate communication channels like SMS or WhatsApp into any program through the Infobip API and its SDKs with only a few lines of code!

Prerequisites

  • Working Go installation
  • Infobip Account
  • Git installation
  • An IDE or Terminal

Project Overview

To use the SMS-enabled features of our zerolog version, follow the following steps:

  1. Create a new Go project.
  2. Clone our zerolog-sms repo.
  3. Get zerolog and replace it with the local version.
  4. Call the Alert() function with your event message.

This demo uses a fork of the official zerolog repository, in which we included a few extra lines of code that do the following:

  1. Add a Mobile logging level
  2. Add an Alert() convenience function to log to the Mobile level
  3. Add the Infobip dependencies and create a sendSMS function to write events.

Now, let’s go through the steps to get your code running!

Create a new Go project

For this step, you can use the terminal or an IDE, as you prefer. You need to create a module to manage dependencies.

Clone our zerolog-sms repo.

Get a copy of our SMS-enabled zerolog by cloning the repo somewhere outside your project folder.

git clone https://github.com/infobip-community/zerolog-sms.git

Get zerolog and replace it with the local version

Install zerolog as you would with a regular dependency:

go get -u github.com/rs/zerolog/log

To use the local zerolog dependency instead of the one from GitHub, you need a replace line in your project’s go.mod file. The path on the right should point to wherever you cloned the zerolog-sms repo. Here’s an example:

replace github.com/rs/zerolog v1.31.0 => ../../Projects/zerolog-sms

Call the Alert() function with your event message

For the following Go code to run correctly, you must first set three environment variables: IB_BASE_URL, IB_API_KEY, and SMS_DESTINATION with your base URL, credentials, and phone number in international format, respectively.

export IB_BASE_URL="<your-base-url>"
export IB_API_KEY="<your-api-key>"
export SMS_DESTINATION="<your-phone-number>"

The base URL and API keys are created when you sign up. You can check them by logging in to your account. You can set these variables however your existing project sets environment variables.

Now, you can call the newly added function Alert() from your project and see the desired log entry directly on your phone.

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Alert("Hello, alert over SMS")
}

And that’s all you need to use this SMS logging functionality. Read on to see how it works.


Now, we’ll describe the steps to add the SMS capabilities to zerolog.

Add a Mobile logging level

First, we enabled a new logging level that will send SMS messages when used. This code goes under the root log.go file:

const (
    // ...
    // MobileLevel defines a mobile log level.
    MobileLevel

This also requires adding a function that returns a new Mobile event under the same log.go file:

// Mobile starts a new message with Mobile level.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Mobile() *Event {
    return l.newEvent(MobileLevel, nil)
}

Additionally, for the log level to display correctly, we need to add a value with the name of the logging level under the root globals.go file:

var(
   // ..
   LevelMobileValue = "mobile"

Add an Alert() convenience function to log to the Mobile level

After the new logging level was added, we created a function that the user can use. This also goes under the root log.go file.

// Alert sends a log event using mobile level and no extra field.
// Arguments are handled in the manner of fmt.Print.
func (l *Logger) Alert(v ...interface{}) {
    if e := l.Mobile(); e.Enabled() {
        e.CallerSkipFrame(1).Msg(fmt.Sprint(v...))
    }
}

This one also needs to be implemented in the log/log.go file, like this:

// Alert sends a log event using MobileLevel level and no extra field.
// Arguments are handled in the manner of fmt.Print.
func Alert(v ...interface{}) {
    Logger.Mobile().CallerSkipFrame(1).Msg(fmt.Sprint(v...))
}

Add the Infobip dependencies and create a sendSMS function to write events

Under the file event.go, we added the dependency to use the Infobip API Go SDK:

    "github.com/infobip-community/infobip-api-go-sdk/v3/pkg/infobip"
    "github.com/infobip-community/infobip-api-go-sdk/v3/pkg/infobip/models"

Then, we created a function to send an SMS to SMS_DESTINATION.

func sendSMS(msg string) {
    client, _ := infobip.NewClientFromEnv()

    destination := os.Getenv("SMS_DESTINATION")

    sms := models.SMSMsg{
    Destinations: []models.SMSDestination{
            {
                To: destination},
            },
            Text: msg,
        }
        request := models.SendSMSRequest{
        Messages: []models.SMSMsg{sms},
    }

    resp, respDetails, _ := client.SMS.Send(context.Background(), request)

    fmt.Println(msg)
    fmt.Println(resp)
    fmt.Println(respDetails)
}

In this function, we make use of the SMS_DESTINATION variable we set in the previous instructions. The other two, IB_API_KEY and IB_BASE_URL, are read directly from the SDK in the NewClientFromEnv function. The next steps are creating an SMSMessage and sending it through the SMS.Send function.

The last step is to call the sendSms function when writing the event.

func (e *Event) write() (err error) {
    if e == nil {
        return nil
    }
    if e.level != Disabled {
        e.buf = enc.AppendEndMarker(e.buf)
        e.buf = enc.AppendLineBreak(e.buf)
        if e.w != nil {
            _, err = e.w.WriteLevel(e.level, e.buf)
        }

        if e.level == MobileLevel {
            sendSms(string(e.buf))
        }
    }
    putEvent(e)
    return
}

Here, we use the write function of Event, which is used by all logging levels, to add an extra action for the particular MobileLevel.

That is all! As you can see, with a few steps, you could adapt the steps we took with zerolog if you wanted to modify any other logger and get notified about important things on your phone. To get a complete overview of all the required changes, check our zerolog fork last changes.

In case you find any errors or you want to know more about response details, please check Infobip Response Status and Error Codes Reference. Go errors can be caught by enabling the anonymous variables _ through code and checking if they are nil or an Error object. To do this in the sendSms function, replace _ with err and check the err variable value after that. For more, check the Error handling and Go guide from the Golang blog.

For a comprehensive guide on sending SMS, be sure to check the documentation page for sending SMS messages.