Newer
Older
Jan Semmelink
committed
import (
"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/number_utils"
Jan Semmelink
committed
"strings"
"time"
"github.com/aws/aws-lambda-go/events"
)
func GenerateIncomingAPILog(startTime time.Time, requestID *string, claim map[string]interface{}, req events.APIGatewayProxyRequest, res events.APIGatewayProxyResponse) ApiLog {
Jan Semmelink
committed
endTime := time.Now()
currentRequestID := ""
if requestID != nil {
currentRequestID = *requestID
}
Jan Semmelink
committed
var authType string
var authUsername string
if req.RequestContext.Identity.CognitoAuthenticationType != "" {
authType = "cognito"
split := strings.Split(req.RequestContext.Identity.CognitoAuthenticationProvider, ":")
if len(split) > 0 {
authUsername = split[len(split)-1] // = part after last ':'
Jan Semmelink
committed
}
} else {
authType = "iam"
split := strings.Split(req.RequestContext.Identity.UserArn, ":user/")
if len(split) > 0 {
authUsername = split[len(split)-1] // = part after ':user/'
Jan Semmelink
committed
}
}
userID, _ := claim["UserID"].(int64)
username, _ := claim["Username"].(string)
accountID, _ := claim["AccountID"].(int64)
providerID, _ := claim["ProviderID"].(int64)
if accountID == 0 {
if accountIDParam, ok := req.QueryStringParameters["account_id"]; ok {
if i64, err := number_utils.StringToInt64(accountIDParam); err == nil && i64 > 0 {
if providerID == 0 {
if providerIDParam, ok := req.QueryStringParameters["provider_id"]; ok {
if i64, err := number_utils.StringToInt64(providerIDParam); err == nil && i64 > 0 {
typeString := "api-incoming"
if funk.Contains(req.Path, "webhook") {
typeString = "webhook-incoming"
}
// Remove the API key in the header
if req.Headers["authorization"] != "" {
req.Headers["authorization"] = "***"
}
if req.Headers["Authorization"] != "" {
req.Headers["Authorization"] = "***"
}
Jan Semmelink
committed
apiLog := ApiLog{
StartTime: startTime,
EndTime: endTime,
DurMs: endTime.Sub(startTime).Milliseconds(),
Jan Semmelink
committed
Method: req.HTTPMethod,
Address: req.RequestContext.DomainName,
Path: req.Path,
ResponseCode: res.StatusCode,
RequestID: currentRequestID,
Jan Semmelink
committed
InitialAuthType: authType,
InitialAuthUsername: authUsername,
SourceIP: req.RequestContext.Identity.SourceIP,
UserAgent: req.RequestContext.Identity.UserAgent,
Jan Semmelink
committed
Username: username,
AccountID: accountID,
Jan Semmelink
committed
Request: ApiLogRequest{
Headers: req.Headers,
QueryParameters: req.QueryStringParameters,
BodySize: len(req.Body),
Jan Semmelink
committed
},
Response: ApiLogResponse{
Headers: res.Headers,
BodySize: len(res.Body),
Body: res.Body,
Jan Semmelink
committed
},
}
// also copy multi-value query parameters to the log as CSV array values
Jan Semmelink
committed
for n, as := range req.MultiValueQueryStringParameters {
apiLog.Request.QueryParameters[n] = "[" + strings.Join(as, ",") + "]"
}
func GenerateOutgoingAPILog(startTime time.Time, requestID *string, claim map[string]interface{}, urlString string, method string, requestBody string, requestHeaders map[string]string, responseBody string, responseHeaders map[string]string, responseCode int) ApiLog {
currentRequestID := ""
if requestID != nil {
currentRequestID = *requestID
}
userID, _ := claim["UserID"].(int64)
username, _ := claim["Username"].(string)
providerID, _ := claim["ProviderID"].(int64)
path := ""
address := ""
parsedURL, err := url.Parse(urlString)
if err == nil {
for n, v := range parsedURL.Query() {
params[n] = strings.Join(v, ",")
}
path = parsedURL.Path
address = parsedURL.Host
Jan Semmelink
committed
}
for k, v := range requestHeaders {
if strings.ToLower(k) == "x-bobgroup-type" && strings.ToLower(v) == "webhook" {
typeString = "webhook-outgoing"
break
}
apiLog := ApiLog{
StartTime: startTime,
EndTime: endTime,
DurMs: endTime.Sub(startTime).Milliseconds(),
Path: path,
Address: address,
RequestID: currentRequestID,
Username: username,
QueryParameters: params,
BodySize: len(requestBody),
BodySize: len(responseBody),
Jan Semmelink
committed
// ApiLog is the SQS event details struct encoded as JSON document, sent to SQS, to be logged for each API handler executed.
Jan Semmelink
committed
type ApiLog struct {
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
DurMs int64 `json:"duration_ms"` // duration in milliseconds
Type string `json:"type"` // incoming-api or outgoing-api
Address string `json:"address"` // server address for incoming and outgoing
Path string `json:"path"`
ResponseCode int `json:"response_code"`
RequestID string `json:"request_id"`
InitialAuthUsername string `json:"initial_auth_username,omitempty"`
InitialAuthType string `json:"initial_auth_type,omitempty"`
AccountID int64 `json:"account_id,omitempty"`
ProviderID int64 `json:"provider_id,omitempty"`
UserID int64 `json:"user_id,omitempty"`
Username string `json:"username,omitempty"`
SourceIP string `json:"source_ip,omitempty"` // only logged for incoming API
UserAgent string `json:"user_agent,omitempty"` // only for incoming, indicate type of browser when UI
Request ApiLogRequest `json:"request"`
Response ApiLogResponse `json:"response"`
Jan Semmelink
committed
}
type ApiLogRequest struct {
Headers map[string]string `json:"headers,omitempty" search:"flattened"`
QueryParameters map[string]string `json:"query_parameters,omitempty" search:"flattened"`
BodySize int `json:"body_size" search:"long"` // set even when body is truncated/omitted
Body string `json:"body,omitempty"` // json body as a string
Jan Semmelink
committed
}
type ApiLogResponse struct {
Headers map[string]string `json:"headers,omitempty" search:"flattened"`
BodySize int `json:"body_size"` // set even when body is truncated/omitted
Body string `json:"body,omitempty"` // json content as a string