Skip to content
Snippets Groups Projects
Select Git revision
  • main default protected
  • trading_hours
  • refactor_trading_hours
  • audit_cleaning_cater_for_non_struct_fields
  • remove-info-logs
  • sl-refactor
  • 18-use-scan-for-param-values
  • 17-order-search-results
  • 4-simplify-framework-2
  • 1-http-error
  • v1.296.0
  • v1.295.0
  • v1.294.0
  • v1.293.0
  • v1.292.0
  • v1.291.0
  • v1.290.0
  • v1.289.0
  • v1.288.0
  • v1.287.0
  • v1.286.0
  • v1.285.0
  • v1.284.0
  • v1.283.0
  • v1.282.0
  • v1.281.0
  • v1.280.0
  • v1.279.0
  • v1.278.0
  • v1.277.0
30 results

api-logs.go

Blame
  • api-logs.go 5.67 KiB
    package api_logs
    
    import (
    	"net/url"
    	"strconv"
    	"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 {
    	endTime := time.Now()
    
    	currentRequestID := ""
    	if requestID != nil {
    		currentRequestID = *requestID
    	}
    
    	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 ':'
    		}
    	} else {
    		authType = "iam"
    		split := strings.Split(req.RequestContext.Identity.UserArn, ":user/")
    		if len(split) > 0 {
    			authUsername = split[len(split)-1] //= part after ':user/'
    		}
    	}
    
    	userID, _ := claim["UserID"].(int64)
    	username, _ := claim["Username"].(string)
    	accountID, _ := claim["AccountID"].(int64)
    	if accountID == 0 {
    		if accountIDParam, ok := req.QueryStringParameters["account_id"]; ok {
    			if i64, err := strconv.ParseInt(accountIDParam, 10, 64); err == nil && i64 > 0 {
    				accountID = i64
    			}
    		}
    	}
    	apiLog := ApiLog{
    		StartTime:           startTime,
    		EndTime:             endTime,
    		DurMs:               endTime.Sub(startTime).Milliseconds(),
    		Type:                "api-incoming",
    		Method:              req.HTTPMethod,
    		Address:             req.RequestContext.DomainName,
    		Path:                req.Path,
    		ResponseCode:        res.StatusCode,
    		RequestID:           currentRequestID,
    		InitialAuthType:     authType,
    		InitialAuthUsername: authUsername,
    		SourceIP:            req.RequestContext.Identity.SourceIP,
    		UserAgent:           req.RequestContext.Identity.UserAgent,
    		UserID:              userID,
    		Username:            username,
    		AccountID:           accountID,
    		Request: ApiLogRequest{
    			Headers:         req.Headers,
    			QueryParameters: req.QueryStringParameters,
    			BodySize:        len(req.Body),
    			Body:            req.Body,
    		},
    		Response: ApiLogResponse{
    			Headers:  res.Headers,
    			BodySize: len(res.Body),
    			Body:     res.Body,
    		},
    	}
    
    	//also copy multi-value query parameters to the log as CSV array values
    	for n, as := range req.MultiValueQueryStringParameters {
    		apiLog.Request.QueryParameters[n] = "[" + strings.Join(as, ",") + "]"
    	}
    
    	return apiLog
    }
    
    func GenerateOutgoingAPILog(startTime time.Time, requestID *string, claim map[string]interface{}, urlString string, method string, requestBody string, requestHeaders map[string]string, responseBody string, responseCode int) ApiLog {
    	endTime := time.Now()
    
    	currentRequestID := ""
    	if requestID != nil {
    		currentRequestID = *requestID
    	}
    
    	userID, _ := claim["UserID"].(int64)
    	username, _ := claim["Username"].(string)
    	accountID, _ := claim["AccountID"].(int64)
    	params := map[string]string{}
    	parsedURL, err := url.Parse(urlString)
    	if err == nil {
    		for n, v := range parsedURL.Query() {
    			params[n] = strings.Join(v, ",")
    		}
    	}
    
    	apiLog := ApiLog{
    		StartTime:    startTime,
    		EndTime:      endTime,
    		DurMs:        endTime.Sub(startTime).Milliseconds(),
    		Type:         "api-outgoing",
    		Method:       method,
    		Path:         parsedURL.Path,
    		Address:      parsedURL.Host,
    		ResponseCode: responseCode,
    		RequestID:    currentRequestID,
    		UserID:       userID,
    		Username:     username,
    		AccountID:    accountID,
    		Request: ApiLogRequest{
    			Headers:         requestHeaders,
    			QueryParameters: params,
    			BodySize:        len(requestBody),
    			Body:            requestBody,
    		},
    		Response: ApiLogResponse{
    			Headers:  requestHeaders,
    			BodySize: len(responseBody),
    			Body:     responseBody,
    		},
    	}
    
    	return apiLog
    }
    
    //ApiLog is the SQS event details struct encoded as JSON document, sent to SQS, to be logged for each API handler executed.
    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
    	Method              string         `json:"method"`
    	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"`
    	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"`
    }
    
    type ApiLogRequest struct {
    	Headers         map[string]string `json:"headers,omitempty"`
    	QueryParameters map[string]string `json:"query_parameters,omitempty"`
    	BodySize        int               `json:"body_size" search:"long"` //set even when body is truncated/omitted
    	Body            string            `json:"body,omitempty"`          //json body as a string
    }
    
    type ApiLogResponse struct {
    	Headers  map[string]string `json:"headers,omitempty"`
    	BodySize int               `json:"body_size"`      //set even when body is truncated/omitted
    	Body     string            `json:"body,omitempty"` //json content as a string
    }