Skip to content

Instantly share code, notes, and snippets.

@saleem-mirza
Last active October 22, 2021 19:04
Show Gist options
  • Save saleem-mirza/004ffee97e38a1488e2ca3107c5785c8 to your computer and use it in GitHub Desktop.
Save saleem-mirza/004ffee97e38a1488e2ca3107c5785c8 to your computer and use it in GitHub Desktop.
Azure Log Analytics Logger in Golang
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"net/http"
"time"
"unicode/utf8"
"strconv"
"bytes"
"strings"
"log"
)
const (
// Replace with your Workspace ID
customerId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// Replace with your Primary or Secondary ID
sharedKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
//Specify the name of the record type that you'll be creating
logType = "GoLogType"
//Specify a field with the created time for the records
timeStampField = "DateValue"
)
func BuildSignature(message, secret string) (string, error) {
keyBytes, err := base64.StdEncoding.DecodeString(secret)
if err != nil {
return "", err
}
mac := hmac.New(sha256.New, keyBytes)
mac.Write([]byte(message))
return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
}
func PostData(data string) (error) {
dateString := time.Now().UTC().Format(time.RFC1123)
dateString = strings.Replace(dateString, "UTC", "GMT", -1)
stringToHash := "POST\n" + strconv.Itoa(utf8.RuneCountInString(data)) + "\napplication/json\n" + "x-ms-date:" + dateString + "\n/api/logs"
hashedString, err := BuildSignature(stringToHash, sharedKey)
if err != nil {
log.Println(err.Error())
return err
}
signature := "SharedKey " + customerId + ":" + hashedString
url := "https://" + customerId + ".ods.opinsights.azure.com/api/logs?api-version=2016-04-01"
client := &http.Client{}
req, err := http.NewRequest("POST", url, bytes.NewReader([]byte(data)))
if err != nil {
return err
}
req.Header.Add("Log-Type", logName)
req.Header.Add("Authorization", signature)
req.Header.Add("Content-Type", "application/json")
req.Header.Add("x-ms-date", dateString)
req.Header.Add("time-generated-field", timeStampField)
resp, err := client.Do(req)
defer resp.Body.Close()
if err == nil {
log.Println(resp.Status)
return nil
}
return err
}
func main() {
var json = `[{"DemoField1":"DemoValue1","DemoField2":"DemoValue2"},{"DemoField3":"DemoValue3"}]`
PostData(json)
}
@wvkranenburg
Copy link

Hi @saleem-mirza! Thanks for this snippet! Really useful! Sometimes I get a 403 status that says my auth header is not correct. It seems related to the contents of my json and the content length. Do you have a clue on how to normalise my json/strings so that this will go correctly?

@wvkranenburg
Copy link

I got the answer from someone on reddit:

utf8.RuneCountInString(data) should just be the length in bytes, not in Runes, so len(data) worked for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment