diff --git a/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/ldx_sync.go b/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/ldx_sync.go index 977e80418..407dea0ce 100644 --- a/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/ldx_sync.go +++ b/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/ldx_sync.go @@ -56,6 +56,29 @@ const ( ErrorDocument0JsonapiVersionN10 ErrorDocument0JsonapiVersion = "1.0" ) +// Defines values for LogMessageLevel. +const ( + LogMessageLevelDebug LogMessageLevel = "debug" + LogMessageLevelError LogMessageLevel = "error" + LogMessageLevelInfo LogMessageLevel = "info" + LogMessageLevelWarn LogMessageLevel = "warn" +) + +// Defines values for LogPostingErrorDocumentJsonapiVersion. +const ( + LogPostingErrorDocumentJsonapiVersionN10 LogPostingErrorDocumentJsonapiVersion = "1.0" +) + +// Defines values for PostLogResponseDataType. +const ( + Log PostLogResponseDataType = "log" +) + +// Defines values for PostLogResponseJsonapiVersion. +const ( + PostLogResponseJsonapiVersionN10 PostLogResponseJsonapiVersion = "1.0" +) + // ActualVersion Resolved API version type ActualVersion = string @@ -393,6 +416,53 @@ type LinkProperty1 struct { Meta *Meta `json:"meta,omitempty"` } +// LogMessage A single log message +type LogMessage struct { + // Level The log level + Level *LogMessageLevel `json:"level,omitempty"` + + // LogMessage The log message content + LogMessage *string `json:"log_message,omitempty"` +} + +// LogMessageLevel The log level +type LogMessageLevel string + +// LogPostingError defines model for LogPostingError. +type LogPostingError struct { + // Detail A human-readable explanation specific to this occurrence of the problem + Detail string `json:"detail"` + + // Status The HTTP status code applicable to this problem + Status string `json:"status"` +} + +// LogPostingErrorDocument defines model for LogPostingErrorDocument. +type LogPostingErrorDocument struct { + Errors []LogPostingError `json:"errors"` + Jsonapi *struct { + Version *LogPostingErrorDocumentJsonapiVersion `json:"version,omitempty"` + } `json:"jsonapi,omitempty"` +} + +// LogPostingErrorDocumentJsonapiVersion defines model for LogPostingErrorDocument.Jsonapi.Version. +type LogPostingErrorDocumentJsonapiVersion string + +// LogSource Source information about the integration that generated all logs in this batch +type LogSource struct { + // IntegrationEnvironment Environment where the integration is running + IntegrationEnvironment *string `json:"integration_environment,omitempty"` + + // IntegrationEnvironmentVersion Version of the integration environment + IntegrationEnvironmentVersion *string `json:"integration_environment_version,omitempty"` + + // IntegrationName Name of the integration (e.g., VS_CODE, JETBRAINS_IDE) + IntegrationName *string `json:"integration_name,omitempty"` + + // IntegrationVersion Version of the integration + IntegrationVersion *string `json:"integration_version,omitempty"` +} + // Meta Free-form object that may contain non-standard information. type Meta map[string]interface{} @@ -430,6 +500,31 @@ type Policy struct { LockedAttributes *[]string `json:"locked_attributes,omitempty"` } +// PostLogResponse defines model for PostLogResponse. +type PostLogResponse struct { + Data struct { + // Id Unique identifier for the log entry + Id openapi_types.UUID `json:"id"` + + // Type Resource type + Type PostLogResponseDataType `json:"type"` + } `json:"data"` + Jsonapi *struct { + Version *PostLogResponseJsonapiVersion `json:"version,omitempty"` + } `json:"jsonapi,omitempty"` + Links *struct { + // Self Link to this resource + Self *string `json:"self,omitempty"` + } `json:"links,omitempty"` + Meta *ResponseMeta `json:"meta,omitempty"` +} + +// PostLogResponseDataType Resource type +type PostLogResponseDataType string + +// PostLogResponseJsonapiVersion defines model for PostLogResponse.Jsonapi.Version. +type PostLogResponseJsonapiVersion string + // ProductConfig defines model for ProductConfig. type ProductConfig struct { // Code Enable Code (SAST) scanning @@ -500,10 +595,16 @@ type N404 = ErrorDocument type N500 = ErrorDocument // ErrorResponseApplicationJSON defines model for ErrorResponse. -type ErrorResponseApplicationJSON = ErrorDocument0 +type ErrorResponseApplicationJSON = LogPostingErrorDocument // ErrorResponseApplicationVndAPIPlusJSON defines model for ErrorResponse. -type ErrorResponseApplicationVndAPIPlusJSON = ErrorDocument0 +type ErrorResponseApplicationVndAPIPlusJSON = LogPostingErrorDocument + +// ErrorResponse0ApplicationJSON defines model for ErrorResponse__0. +type ErrorResponse0ApplicationJSON = ErrorDocument0 + +// ErrorResponse0ApplicationVndAPIPlusJSON defines model for ErrorResponse__0. +type ErrorResponse0ApplicationVndAPIPlusJSON = ErrorDocument0 // DeleteConfigParams defines parameters for DeleteConfig. type DeleteConfigParams struct { @@ -624,12 +725,29 @@ type CreateConfigParams struct { RemoteUrl *string `form:"remote_url,omitempty" json:"remote_url,omitempty"` } +// CreateLogMessageJSONBody defines parameters for CreateLogMessage. +type CreateLogMessageJSONBody struct { + LogMessages []LogMessage `json:"log_messages"` + + // Source Source information about the integration that generated all logs in this batch + Source LogSource `json:"source"` +} + +// CreateLogMessageParams defines parameters for CreateLogMessage. +type CreateLogMessageParams struct { + // Version API version in format YYYY-MM-DD + Version string `form:"version" json:"version"` +} + // UpdateConfigJSONRequestBody defines body for UpdateConfig for application/json ContentType. type UpdateConfigJSONRequestBody = ConfigurationRequest // CreateConfigJSONRequestBody defines body for CreateConfig for application/json ContentType. type CreateConfigJSONRequestBody = ConfigurationRequest +// CreateLogMessageJSONRequestBody defines body for CreateLogMessage for application/json ContentType. +type CreateLogMessageJSONRequestBody CreateLogMessageJSONBody + // AsLinkProperty0 returns the union data inside the LinkProperty as a LinkProperty0 func (t LinkProperty) AsLinkProperty0() (LinkProperty0, error) { var body LinkProperty0 @@ -781,6 +899,11 @@ type ClientInterface interface { CreateConfig(ctx context.Context, params *CreateConfigParams, body CreateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // CreateLogMessageWithBody request with any body + CreateLogMessageWithBody(ctx context.Context, params *CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) + + CreateLogMessage(ctx context.Context, params *CreateLogMessageParams, body CreateLogMessageJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // ListAPIVersions request ListAPIVersions(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -860,6 +983,30 @@ func (c *Client) CreateConfig(ctx context.Context, params *CreateConfigParams, b return c.Client.Do(req) } +func (c *Client) CreateLogMessageWithBody(ctx context.Context, params *CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateLogMessageRequestWithBody(c.Server, params, contentType, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + +func (c *Client) CreateLogMessage(ctx context.Context, params *CreateLogMessageParams, body CreateLogMessageJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewCreateLogMessageRequest(c.Server, params, body) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) ListAPIVersions(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewListAPIVersionsRequest(c.Server) if err != nil { @@ -919,6 +1066,7 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } if params.Tenant != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tenant", runtime.ParamLocationQuery, *params.Tenant); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -930,9 +1078,11 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } if params.Group != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "group", runtime.ParamLocationQuery, *params.Group); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -944,9 +1094,11 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } if params.Org != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "org", runtime.ParamLocationQuery, *params.Org); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -958,9 +1110,11 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } if params.AssetId != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "asset_id", runtime.ParamLocationQuery, *params.AssetId); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -972,9 +1126,11 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } if params.ProjectName != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "project_name", runtime.ParamLocationQuery, *params.ProjectName); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -986,9 +1142,11 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } if params.RemoteUrl != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "remote_url", runtime.ParamLocationQuery, *params.RemoteUrl); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1000,6 +1158,7 @@ func NewDeleteConfigRequest(server string, params *DeleteConfigParams) (*http.Re } } } + } queryURL.RawQuery = queryValues.Encode() @@ -1048,6 +1207,7 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } if params.Org != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "org", runtime.ParamLocationQuery, *params.Org); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1059,9 +1219,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.AssetId != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "asset_id", runtime.ParamLocationQuery, *params.AssetId); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1073,9 +1235,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.ProjectName != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "project_name", runtime.ParamLocationQuery, *params.ProjectName); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1087,9 +1251,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.RemoteUrl != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "remote_url", runtime.ParamLocationQuery, *params.RemoteUrl); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1101,9 +1267,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.Group != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "group", runtime.ParamLocationQuery, *params.Group); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1115,9 +1283,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.Tenant != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tenant", runtime.ParamLocationQuery, *params.Tenant); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1129,9 +1299,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.IntegrationName != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "integration_name", runtime.ParamLocationQuery, *params.IntegrationName); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1143,9 +1315,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.IntegrationVersion != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "integration_version", runtime.ParamLocationQuery, *params.IntegrationVersion); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1157,9 +1331,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.IntegrationEnvironment != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "integration_environment", runtime.ParamLocationQuery, *params.IntegrationEnvironment); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1171,9 +1347,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.IntegrationEnvironmentVersion != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "integration_environment_version", runtime.ParamLocationQuery, *params.IntegrationEnvironmentVersion); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1185,9 +1363,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.StartingAfter != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "starting_after", runtime.ParamLocationQuery, *params.StartingAfter); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1199,9 +1379,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.EndingBefore != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ending_before", runtime.ParamLocationQuery, *params.EndingBefore); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1213,9 +1395,11 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } if params.Limit != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1227,6 +1411,7 @@ func NewGetConfigRequest(server string, params *GetConfigParams) (*http.Request, } } } + } queryURL.RawQuery = queryValues.Encode() @@ -1286,6 +1471,7 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } if params.Tenant != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tenant", runtime.ParamLocationQuery, *params.Tenant); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1297,9 +1483,11 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } if params.Group != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "group", runtime.ParamLocationQuery, *params.Group); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1311,9 +1499,11 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } if params.Org != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "org", runtime.ParamLocationQuery, *params.Org); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1325,9 +1515,11 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } if params.AssetId != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "asset_id", runtime.ParamLocationQuery, *params.AssetId); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1339,9 +1531,11 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } if params.ProjectName != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "project_name", runtime.ParamLocationQuery, *params.ProjectName); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1353,9 +1547,11 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } if params.RemoteUrl != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "remote_url", runtime.ParamLocationQuery, *params.RemoteUrl); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1367,6 +1563,7 @@ func NewUpdateConfigRequestWithBody(server string, params *UpdateConfigParams, c } } } + } queryURL.RawQuery = queryValues.Encode() @@ -1428,6 +1625,7 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } if params.Tenant != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tenant", runtime.ParamLocationQuery, *params.Tenant); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1439,9 +1637,11 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + } if params.Group != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "group", runtime.ParamLocationQuery, *params.Group); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1453,9 +1653,11 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + } if params.Org != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "org", runtime.ParamLocationQuery, *params.Org); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1467,9 +1669,11 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + } if params.AssetId != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "asset_id", runtime.ParamLocationQuery, *params.AssetId); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1481,9 +1685,11 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + } if params.ProjectName != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "project_name", runtime.ParamLocationQuery, *params.ProjectName); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1495,9 +1701,11 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + } if params.RemoteUrl != nil { + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "remote_url", runtime.ParamLocationQuery, *params.RemoteUrl); err != nil { return nil, err } else if parsed, err := url.ParseQuery(queryFrag); err != nil { @@ -1509,6 +1717,65 @@ func NewCreateConfigRequestWithBody(server string, params *CreateConfigParams, c } } } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("POST", queryURL.String(), body) + if err != nil { + return nil, err + } + + req.Header.Add("Content-Type", contentType) + + return req, nil +} + +// NewCreateLogMessageRequest calls the generic CreateLogMessage builder with application/json body +func NewCreateLogMessageRequest(server string, params *CreateLogMessageParams, body CreateLogMessageJSONRequestBody) (*http.Request, error) { + var bodyReader io.Reader + buf, err := json.Marshal(body) + if err != nil { + return nil, err + } + bodyReader = bytes.NewReader(buf) + return NewCreateLogMessageRequestWithBody(server, params, "application/json", bodyReader) +} + +// NewCreateLogMessageRequestWithBody generates requests for CreateLogMessage with any type of body +func NewCreateLogMessageRequestWithBody(server string, params *CreateLogMessageParams, contentType string, body io.Reader) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/local_client_connector/logs") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "version", runtime.ParamLocationQuery, params.Version); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } } queryURL.RawQuery = queryValues.Encode() @@ -1644,6 +1911,11 @@ type ClientWithResponsesInterface interface { CreateConfigWithResponse(ctx context.Context, params *CreateConfigParams, body CreateConfigJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateConfigResponse, error) + // CreateLogMessageWithBodyWithResponse request with any body + CreateLogMessageWithBodyWithResponse(ctx context.Context, params *CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateLogMessageResponse, error) + + CreateLogMessageWithResponse(ctx context.Context, params *CreateLogMessageParams, body CreateLogMessageJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateLogMessageResponse, error) + // ListAPIVersionsWithResponse request ListAPIVersionsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListAPIVersionsResponse, error) @@ -1654,12 +1926,12 @@ type ClientWithResponsesInterface interface { type DeleteConfigResponse struct { Body []byte HTTPResponse *http.Response - JSON401 *ErrorResponseApplicationJSON - ApplicationvndApiJSON401 *ErrorResponseApplicationVndAPIPlusJSON - JSON404 *ErrorResponseApplicationJSON - ApplicationvndApiJSON404 *ErrorResponseApplicationVndAPIPlusJSON - JSON500 *ErrorResponseApplicationJSON - ApplicationvndApiJSON500 *ErrorResponseApplicationVndAPIPlusJSON + JSON401 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON401 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON404 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON404 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON500 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON500 *ErrorResponse0ApplicationVndAPIPlusJSON } // Status returns HTTPResponse.Status @@ -1683,14 +1955,14 @@ type GetConfigResponse struct { HTTPResponse *http.Response JSON200 *ConfigResponse ApplicationvndApiJSON200 *ConfigResponse - JSON400 *ErrorResponseApplicationJSON - ApplicationvndApiJSON400 *ErrorResponseApplicationVndAPIPlusJSON - JSON401 *ErrorResponseApplicationJSON - ApplicationvndApiJSON401 *ErrorResponseApplicationVndAPIPlusJSON - JSON404 *ErrorResponseApplicationJSON - ApplicationvndApiJSON404 *ErrorResponseApplicationVndAPIPlusJSON - JSON500 *ErrorResponseApplicationJSON - ApplicationvndApiJSON500 *ErrorResponseApplicationVndAPIPlusJSON + JSON400 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON400 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON401 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON401 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON404 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON404 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON500 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON500 *ErrorResponse0ApplicationVndAPIPlusJSON } // Status returns HTTPResponse.Status @@ -1714,14 +1986,14 @@ type UpdateConfigResponse struct { HTTPResponse *http.Response JSON200 *ConfigResponse ApplicationvndApiJSON200 *ConfigResponse - JSON400 *ErrorResponseApplicationJSON - ApplicationvndApiJSON400 *ErrorResponseApplicationVndAPIPlusJSON - JSON401 *ErrorResponseApplicationJSON - ApplicationvndApiJSON401 *ErrorResponseApplicationVndAPIPlusJSON - JSON404 *ErrorResponseApplicationJSON - ApplicationvndApiJSON404 *ErrorResponseApplicationVndAPIPlusJSON - JSON500 *ErrorResponseApplicationJSON - ApplicationvndApiJSON500 *ErrorResponseApplicationVndAPIPlusJSON + JSON400 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON400 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON401 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON401 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON404 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON404 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON500 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON500 *ErrorResponse0ApplicationVndAPIPlusJSON } // Status returns HTTPResponse.Status @@ -1745,6 +2017,37 @@ type CreateConfigResponse struct { HTTPResponse *http.Response JSON201 *ConfigResponse ApplicationvndApiJSON201 *ConfigResponse + JSON400 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON400 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON401 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON401 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON409 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON409 *ErrorResponse0ApplicationVndAPIPlusJSON + JSON500 *ErrorResponse0ApplicationJSON + ApplicationvndApiJSON500 *ErrorResponse0ApplicationVndAPIPlusJSON +} + +// Status returns HTTPResponse.Status +func (r CreateConfigResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r CreateConfigResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + +type CreateLogMessageResponse struct { + Body []byte + HTTPResponse *http.Response + JSON201 *PostLogResponse + ApplicationvndApiJSON201 *PostLogResponse JSON400 *ErrorResponseApplicationJSON ApplicationvndApiJSON400 *ErrorResponseApplicationVndAPIPlusJSON JSON401 *ErrorResponseApplicationJSON @@ -1756,7 +2059,7 @@ type CreateConfigResponse struct { } // Status returns HTTPResponse.Status -func (r CreateConfigResponse) Status() string { +func (r CreateLogMessageResponse) Status() string { if r.HTTPResponse != nil { return r.HTTPResponse.Status } @@ -1764,7 +2067,7 @@ func (r CreateConfigResponse) Status() string { } // StatusCode returns HTTPResponse.StatusCode -func (r CreateConfigResponse) StatusCode() int { +func (r CreateLogMessageResponse) StatusCode() int { if r.HTTPResponse != nil { return r.HTTPResponse.StatusCode } @@ -1875,6 +2178,23 @@ func (c *ClientWithResponses) CreateConfigWithResponse(ctx context.Context, para return ParseCreateConfigResponse(rsp) } +// CreateLogMessageWithBodyWithResponse request with arbitrary body returning *CreateLogMessageResponse +func (c *ClientWithResponses) CreateLogMessageWithBodyWithResponse(ctx context.Context, params *CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateLogMessageResponse, error) { + rsp, err := c.CreateLogMessageWithBody(ctx, params, contentType, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateLogMessageResponse(rsp) +} + +func (c *ClientWithResponses) CreateLogMessageWithResponse(ctx context.Context, params *CreateLogMessageParams, body CreateLogMessageJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateLogMessageResponse, error) { + rsp, err := c.CreateLogMessage(ctx, params, body, reqEditors...) + if err != nil { + return nil, err + } + return ParseCreateLogMessageResponse(rsp) +} + // ListAPIVersionsWithResponse request returning *ListAPIVersionsResponse func (c *ClientWithResponses) ListAPIVersionsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListAPIVersionsResponse, error) { rsp, err := c.ListAPIVersions(ctx, reqEditors...) @@ -1908,42 +2228,42 @@ func ParseDeleteConfigResponse(rsp *http.Response) (*DeleteConfigResponse, error switch { case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON401 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON404 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON500 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON401 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON404 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -1976,28 +2296,28 @@ func ParseGetConfigResponse(rsp *http.Response) (*GetConfigResponse, error) { response.JSON200 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 400: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON400 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON401 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON404 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -2011,28 +2331,28 @@ func ParseGetConfigResponse(rsp *http.Response) (*GetConfigResponse, error) { response.ApplicationvndApiJSON200 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 400: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON400 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON401 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON404 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -2065,28 +2385,28 @@ func ParseUpdateConfigResponse(rsp *http.Response) (*UpdateConfigResponse, error response.JSON200 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 400: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON400 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON401 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.JSON404 = &dest case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationJSON + var dest ErrorResponse0ApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -2100,28 +2420,28 @@ func ParseUpdateConfigResponse(rsp *http.Response) (*UpdateConfigResponse, error response.ApplicationvndApiJSON200 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 400: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON400 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 401: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON401 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 404: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } response.ApplicationvndApiJSON404 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 500: - var dest ErrorResponseApplicationVndAPIPlusJSON + var dest ErrorResponse0ApplicationVndAPIPlusJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -2153,6 +2473,95 @@ func ParseCreateConfigResponse(rsp *http.Response) (*CreateConfigResponse, error } response.JSON201 = &dest + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 400: + var dest ErrorResponse0ApplicationJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 401: + var dest ErrorResponse0ApplicationJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 409: + var dest ErrorResponse0ApplicationJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON409 = &dest + + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 500: + var dest ErrorResponse0ApplicationJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 201: + var dest ConfigResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndApiJSON201 = &dest + + case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 400: + var dest ErrorResponse0ApplicationVndAPIPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndApiJSON400 = &dest + + case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 401: + var dest ErrorResponse0ApplicationVndAPIPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndApiJSON401 = &dest + + case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 409: + var dest ErrorResponse0ApplicationVndAPIPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndApiJSON409 = &dest + + case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 500: + var dest ErrorResponse0ApplicationVndAPIPlusJSON + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.ApplicationvndApiJSON500 = &dest + + } + + return response, nil +} + +// ParseCreateLogMessageResponse parses an HTTP response from a CreateLogMessageWithResponse call +func ParseCreateLogMessageResponse(rsp *http.Response) (*CreateLogMessageResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &CreateLogMessageResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 201: + var dest PostLogResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON201 = &dest + case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 400: var dest ErrorResponseApplicationJSON if err := json.Unmarshal(bodyBytes, &dest); err != nil { @@ -2182,7 +2591,7 @@ func ParseCreateConfigResponse(rsp *http.Response) (*CreateConfigResponse, error response.JSON500 = &dest case rsp.Header.Get("Content-Type") == "application/vnd.api+json" && rsp.StatusCode == 201: - var dest ConfigResponse + var dest PostLogResponse if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } diff --git a/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/spec.yaml b/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/spec.yaml index d2ffacd1d..61f2d0356 100644 --- a/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/spec.yaml +++ b/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15/spec.yaml @@ -160,6 +160,28 @@ components: sunset: $ref: '#/components/headers/SunsetHeader' ErrorResponse: + content: + application/json: + schema: + $ref: '#/components/schemas/LogPostingErrorDocument' + application/vnd.api+json: + schema: + $ref: '#/components/schemas/LogPostingErrorDocument' + description: Error response + headers: + deprecation: + $ref: '#/components/headers/Deprecation' + snyk-request-id: + $ref: '#/components/headers/SnykRequestId' + snyk-version-lifecycle-stage: + $ref: '#/components/headers/SnykVersionLifecycleStage' + snyk-version-requested: + $ref: '#/components/headers/SnykVersionRequested' + snyk-version-served: + $ref: '#/components/headers/SnykVersionServed' + sunset: + $ref: '#/components/headers/Sunset' + ErrorResponse__0: content: application/json: schema: @@ -790,6 +812,82 @@ components: required: - href type: object + LogMessage: + additionalProperties: false + description: A single log message + properties: + level: + description: The log level + enum: + - debug + - info + - warn + - error + example: info + type: string + log_message: + description: The log message content + example: Hello, World! + type: string + type: object + LogPostingError: + additionalProperties: false + properties: + detail: + description: A human-readable explanation specific to this occurrence of + the problem + example: Invalid request body + type: string + status: + description: The HTTP status code applicable to this problem + example: "400" + type: string + required: + - detail + - status + type: object + LogPostingErrorDocument: + additionalProperties: false + properties: + errors: + items: + $ref: '#/components/schemas/LogPostingError' + minItems: 1 + type: array + jsonapi: + additionalProperties: false + properties: + version: + enum: + - "1.0" + example: "1.0" + type: string + type: object + required: + - errors + type: object + LogSource: + additionalProperties: false + description: Source information about the integration that generated all logs + in this batch + properties: + integration_environment: + description: Environment where the integration is running + example: production + type: string + integration_environment_version: + description: Version of the integration environment + example: 1.85.0 + type: string + integration_name: + description: Name of the integration (e.g., VS_CODE, JETBRAINS_IDE) + example: VS_CODE + type: string + integration_version: + description: Version of the integration + example: 1.2.3 + type: string + type: object Meta: additionalProperties: true description: Free-form object that may contain non-standard information. @@ -858,6 +956,50 @@ components: type: string type: array type: object + PostLogResponse: + additionalProperties: false + properties: + data: + additionalProperties: false + properties: + id: + description: Unique identifier for the log entry + example: 123e4567-e89b-12d3-a456-426614174000 + format: uuid + type: string + type: + description: Resource type + enum: + - log + example: log + type: string + required: + - id + - type + type: object + jsonapi: + additionalProperties: false + properties: + version: + enum: + - "1.0" + example: "1.0" + type: string + type: object + links: + additionalProperties: false + properties: + self: + description: Link to this resource + example: https://api.snyk.io/rest/remote-client-connector/logs + format: uri + type: string + type: object + meta: + $ref: '#/components/schemas/ResponseMeta' + required: + - data + type: object ProductConfig: additionalProperties: false properties: @@ -1012,11 +1154,11 @@ paths: sunset: $ref: '#/components/headers/Sunset' "401": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "404": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "500": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' summary: Delete configuration tags: - Configuration @@ -1174,13 +1316,13 @@ paths: sunset: $ref: '#/components/headers/Sunset' "400": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "401": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "404": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "500": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' summary: Get configuration with automatic organization selection tags: - Configuration @@ -1279,13 +1421,13 @@ paths: sunset: $ref: '#/components/headers/Sunset' "400": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "401": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "404": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' "500": - $ref: '#/components/responses/ErrorResponse' + $ref: '#/components/responses/ErrorResponse__0' summary: Update configuration tags: - Configuration @@ -1383,6 +1525,83 @@ paths: $ref: '#/components/headers/SnykVersionServed' sunset: $ref: '#/components/headers/Sunset' + "400": + $ref: '#/components/responses/ErrorResponse__0' + "401": + $ref: '#/components/responses/ErrorResponse__0' + "409": + $ref: '#/components/responses/ErrorResponse__0' + "500": + $ref: '#/components/responses/ErrorResponse__0' + summary: Create configuration + tags: + - Configuration + x-snyk-api-lifecycle: released + x-snyk-api-owners: + - '@snyk/ide' + x-snyk-api-releases: + - 2024-10-15~beta + x-snyk-api-resource: config + x-snyk-api-stability: beta + x-snyk-api-version: 2024-10-15~beta + x-stability-level: beta + /local_client_connector/logs: + post: + description: Post a log message by logging it in the service + operationId: createLogMessage + parameters: + - description: API version in format YYYY-MM-DD + in: query + name: version + required: true + schema: + example: "2025-07-29" + pattern: ^\d{4}-\d{2}-\d{2}$ + type: string + requestBody: + content: + application/json: + schema: + properties: + log_messages: + items: + $ref: '#/components/schemas/LogMessage' + type: array + source: + $ref: '#/components/schemas/LogSource' + required: + - log_messages + - source + type: object + required: true + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/PostLogResponse' + application/vnd.api+json: + schema: + $ref: '#/components/schemas/PostLogResponse' + description: Log message posted successfully + headers: + deprecation: + $ref: '#/components/headers/Deprecation' + location: + description: URI of the created resource + schema: + format: uri + type: string + snyk-request-id: + $ref: '#/components/headers/SnykRequestId' + snyk-version-lifecycle-stage: + $ref: '#/components/headers/SnykVersionLifecycleStage' + snyk-version-requested: + $ref: '#/components/headers/SnykVersionRequested' + snyk-version-served: + $ref: '#/components/headers/SnykVersionServed' + sunset: + $ref: '#/components/headers/Sunset' "400": $ref: '#/components/responses/ErrorResponse' "401": @@ -1391,15 +1610,19 @@ paths: $ref: '#/components/responses/ErrorResponse' "500": $ref: '#/components/responses/ErrorResponse' - summary: Create configuration + summary: Post a log message by logging it in the service tags: - - Configuration + - Logging + x-cerberus: + authorization: + reason: org-scoped authorization is not sufficient here. + skip: true x-snyk-api-lifecycle: released x-snyk-api-owners: - '@snyk/ide' x-snyk-api-releases: - 2024-10-15~beta - x-snyk-api-resource: config + x-snyk-api-resource: logs x-snyk-api-stability: beta x-snyk-api-version: 2024-10-15~beta x-stability-level: beta diff --git a/pkg/apiclients/ldx_sync_config/mocks/ldx_sync.go b/pkg/apiclients/ldx_sync_config/mocks/ldx_sync.go index d7fa1cb52..0a7b9d856 100644 --- a/pkg/apiclients/ldx_sync_config/mocks/ldx_sync.go +++ b/pkg/apiclients/ldx_sync_config/mocks/ldx_sync.go @@ -115,6 +115,46 @@ func (mr *MockClientInterfaceMockRecorder) CreateConfigWithBody(ctx, params, con return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConfigWithBody", reflect.TypeOf((*MockClientInterface)(nil).CreateConfigWithBody), varargs...) } +// CreateLogMessage mocks base method. +func (m *MockClientInterface) CreateLogMessage(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*http.Response, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, params, body} + for _, a := range reqEditors { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateLogMessage", varargs...) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateLogMessage indicates an expected call of CreateLogMessage. +func (mr *MockClientInterfaceMockRecorder) CreateLogMessage(ctx, params, body interface{}, reqEditors ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, params, body}, reqEditors...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLogMessage", reflect.TypeOf((*MockClientInterface)(nil).CreateLogMessage), varargs...) +} + +// CreateLogMessageWithBody mocks base method. +func (m *MockClientInterface) CreateLogMessageWithBody(ctx context.Context, params *v20241015.CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...v20241015.RequestEditorFn) (*http.Response, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, params, contentType, body} + for _, a := range reqEditors { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateLogMessageWithBody", varargs...) + ret0, _ := ret[0].(*http.Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateLogMessageWithBody indicates an expected call of CreateLogMessageWithBody. +func (mr *MockClientInterfaceMockRecorder) CreateLogMessageWithBody(ctx, params, contentType, body interface{}, reqEditors ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, params, contentType, body}, reqEditors...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLogMessageWithBody", reflect.TypeOf((*MockClientInterface)(nil).CreateLogMessageWithBody), varargs...) +} + // DeleteConfig mocks base method. func (m *MockClientInterface) DeleteConfig(ctx context.Context, params *v20241015.DeleteConfigParams, reqEditors ...v20241015.RequestEditorFn) (*http.Response, error) { m.ctrl.T.Helper() @@ -298,6 +338,46 @@ func (mr *MockClientWithResponsesInterfaceMockRecorder) CreateConfigWithResponse return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConfigWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).CreateConfigWithResponse), varargs...) } +// CreateLogMessageWithBodyWithResponse mocks base method. +func (m *MockClientWithResponsesInterface) CreateLogMessageWithBodyWithResponse(ctx context.Context, params *v20241015.CreateLogMessageParams, contentType string, body io.Reader, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, params, contentType, body} + for _, a := range reqEditors { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateLogMessageWithBodyWithResponse", varargs...) + ret0, _ := ret[0].(*v20241015.CreateLogMessageResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateLogMessageWithBodyWithResponse indicates an expected call of CreateLogMessageWithBodyWithResponse. +func (mr *MockClientWithResponsesInterfaceMockRecorder) CreateLogMessageWithBodyWithResponse(ctx, params, contentType, body interface{}, reqEditors ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, params, contentType, body}, reqEditors...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLogMessageWithBodyWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).CreateLogMessageWithBodyWithResponse), varargs...) +} + +// CreateLogMessageWithResponse mocks base method. +func (m *MockClientWithResponsesInterface) CreateLogMessageWithResponse(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, params, body} + for _, a := range reqEditors { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateLogMessageWithResponse", varargs...) + ret0, _ := ret[0].(*v20241015.CreateLogMessageResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateLogMessageWithResponse indicates an expected call of CreateLogMessageWithResponse. +func (mr *MockClientWithResponsesInterfaceMockRecorder) CreateLogMessageWithResponse(ctx, params, body interface{}, reqEditors ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, params, body}, reqEditors...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateLogMessageWithResponse", reflect.TypeOf((*MockClientWithResponsesInterface)(nil).CreateLogMessageWithResponse), varargs...) +} + // DeleteConfigWithResponse mocks base method. func (m *MockClientWithResponsesInterface) DeleteConfigWithResponse(ctx context.Context, params *v20241015.DeleteConfigParams, reqEditors ...v20241015.RequestEditorFn) (*v20241015.DeleteConfigResponse, error) { m.ctrl.T.Helper() diff --git a/pkg/apiclients/ldx_sync_config/resolver_test.go b/pkg/apiclients/ldx_sync_config/resolver_test.go index 1d0e30f8b..d71f5bdc7 100644 --- a/pkg/apiclients/ldx_sync_config/resolver_test.go +++ b/pkg/apiclients/ldx_sync_config/resolver_test.go @@ -254,7 +254,7 @@ func TestResolveOrganization(t *testing.T) { mock.EXPECT(). GetConfigWithResponse(gomock.Any(), gomock.Any()). Return(&v20241015.GetConfigResponse{ - JSON404: &v20241015.ErrorResponseApplicationJSON{}, + JSON404: &v20241015.ErrorResponse0ApplicationJSON{}, HTTPResponse: &http.Response{StatusCode: http.StatusNotFound}, }, nil) }, diff --git a/pkg/logging/apiLogWriter.go b/pkg/logging/apiLogWriter.go new file mode 100644 index 000000000..231f3e148 --- /dev/null +++ b/pkg/logging/apiLogWriter.go @@ -0,0 +1,343 @@ +/* + * © 2025 Snyk Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package logging + +import ( + "context" + "encoding/json" + "fmt" + "sync" + "time" + + "github.com/rs/zerolog" + + v20241015 "github.com/snyk/go-application-framework/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15" +) + +const ( + // MaxPayloadSize is the maximum size in bytes for a single API request (1MB) + MaxPayloadSize = 1024 * 1024 // 1MB + + // DefaultMaxBufferSize is the default maximum buffer size in bytes (10MB) + DefaultMaxBufferSize = 10 * 1024 * 1024 // 10MB +) + +// LogEntry represents a single log message with its level and timestamp +type LogEntry struct { + Level zerolog.Level `json:"level"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` +} + +func (l *LogEntry) toJSON() ([]byte, error) { + return json.Marshal(toLogMessage(l)) +} + +// Batch represents a collection of log entries that will be sent together +type Batch []LogEntry + +// Size returns the approximate serialized JSON size of the batch in bytes +func (b Batch) Size() (int, error) { + if len(b) == 0 { + return 2, nil // Empty array: [] + } + + totalSize := 2 // Account for array brackets [] + for i, entry := range b { + entryBytes, err := entry.toJSON() + if err != nil { + return 0, err + } + totalSize += len(entryBytes) + if i < len(b)-1 { + totalSize++ // Add comma separator + } + } + return totalSize, nil +} + +// toLogMessage converts a LogEntry to the API LogMessage format +func toLogMessage(entry *LogEntry) v20241015.LogMessage { + level := convertLogLevel(entry.Level) + message := entry.Message + return v20241015.LogMessage{ + Level: &level, + LogMessage: &message, + } +} + +// toAPIFormat converts the batch to a slice of LogMessage +func (b Batch) toAPIFormat() []v20241015.LogMessage { + var logMessages []v20241015.LogMessage + for _, entry := range b { + logMessages = append(logMessages, toLogMessage(&entry)) + } + return logMessages +} + +// APILogWriterConfig holds configuration for the API log writer +type APILogWriterConfig struct { + // MaxBufferSize is the maximum buffer size in bytes (default: 10MB) + MaxBufferSize int + // TriggerLevel is the minimum log level that triggers sending the buffer + TriggerLevel zerolog.Level + // LdxSyncClient is the LDX Sync API client for sending logs + LdxSyncClient v20241015.ClientWithResponsesInterface + // LogSource contains integration information for the log source + LogSource v20241015.LogSource + // OnError is called when sending logs fails (optional) + OnError func(error) +} + +// APILogWriter buffers log messages and sends them to an API endpoint +// when a log message with level >= TriggerLevel is received +type APILogWriter struct { + mu sync.RWMutex + config APILogWriterConfig + buffer []LogEntry + currentBufferSize int // Current buffer size in bytes +} + +// NewAPILogWriter creates a new API log writer with the given configuration +func NewAPILogWriter(config APILogWriterConfig) *APILogWriter { + if config.MaxBufferSize <= 0 { + config.MaxBufferSize = DefaultMaxBufferSize + } + // If TriggerLevel is not set (default zero value is DebugLevel), + // set it to ErrorLevel as a reasonable default for API logging + if config.TriggerLevel == 0 { + config.TriggerLevel = zerolog.ErrorLevel // default trigger level + } + return &APILogWriter{ + config: config, + buffer: make([]LogEntry, 0), + currentBufferSize: 0, + } +} + +// WriteLevel implements zerolog.LevelWriter +func (w *APILogWriter) WriteLevel(level zerolog.Level, p []byte) (int, error) { + // First write to underlying writer if present + var writeErr error + bytesWritten := len(p) + // Add to buffer + w.mu.Lock() + entry := LogEntry{ + Level: level, + Message: string(p), + Timestamp: time.Now(), + } + + // Calculate approximate entry size + entrySize := len(p) + 50 // Message + overhead for level, timestamp, JSON structure + + // Add entry to buffer + w.buffer = append(w.buffer, entry) + w.currentBufferSize += entrySize + + // Trim buffer if it exceeds max size (keep most recent entries) + for w.currentBufferSize > w.config.MaxBufferSize && len(w.buffer) > 0 { + // Remove oldest entry + removedEntry := w.buffer[0] + removedSize := len(removedEntry.Message) + 50 + w.buffer = w.buffer[1:] + w.currentBufferSize -= removedSize + } + + // Check if we should trigger a send + shouldSend := level >= w.config.TriggerLevel + var bufferCopy []LogEntry + if shouldSend { + // Create a copy of the buffer to send + bufferCopy = make([]LogEntry, len(w.buffer)) + copy(bufferCopy, w.buffer) + // Clear the buffer after copying + w.buffer = make([]LogEntry, 0) + w.currentBufferSize = 0 + } + w.mu.Unlock() + + // Send logs asynchronously if triggered + if shouldSend && len(bufferCopy) > 0 { + go w.sendLogs(bufferCopy) + } + + return bytesWritten, writeErr +} + +// Write implements io.Writer interface +func (w *APILogWriter) Write(p []byte) (int, error) { + // Default to Info level when no level is specified + return w.WriteLevel(zerolog.InfoLevel, p) +} + +// sendLogs sends the buffered logs to the API endpoint in batches to ensure +// each payload is under MaxPayloadSize (1MB) +func (w *APILogWriter) sendLogs(entries []LogEntry) { + if w.config.LdxSyncClient == nil { + return + } + + // Split entries into batches based on payload size + batches := w.batchEntriesBySize(entries) + + // Send each batch + for _, batch := range batches { + w.sendBatch(batch) + } +} + +// batchEntriesBySize splits log entries into batches where each batch's +// serialized JSON payload is less than MaxPayloadSize +func (w *APILogWriter) batchEntriesBySize(entries []LogEntry) []Batch { + if len(entries) == 0 { + return nil + } + + var batches []Batch + var currentBatch Batch + var currentSize int + + for _, entry := range entries { + // Create a temporary batch with just this entry to get its size + entryBytes, err := entry.toJSON() + if err != nil { + // If we can't marshal, skip this entry + continue + } + entrySize := len(entryBytes) + 1 // +1 for comma in JSON array + + // If this single entry exceeds max size, skip it (log error) + if entrySize > MaxPayloadSize { + w.handleError(fmt.Errorf("single log entry exceeds maximum payload size: %d bytes", entrySize)) + continue + } + + // If adding this entry would exceed max size, start a new batch + // Account for JSON array overhead: [], commas between entries + estimatedBatchSize := currentSize + entrySize + 2 // +2 for array brackets + if len(currentBatch) > 0 && estimatedBatchSize > MaxPayloadSize { + batches = append(batches, currentBatch) + currentBatch = Batch{entry} + currentSize = entrySize + } else { + currentBatch = append(currentBatch, entry) + currentSize += entrySize + } + } + + // Add the last batch if it has entries + if len(currentBatch) > 0 { + batches = append(batches, currentBatch) + } + + return batches +} + +// sendBatch sends a single batch of log entries to the API +func (w *APILogWriter) sendBatch(batch Batch) { + // Convert batch to API format + logMessages := batch.toAPIFormat() + + // Create request body with log messages and source + requestBody := v20241015.CreateLogMessageJSONRequestBody{ + LogMessages: logMessages, + Source: w.config.LogSource, + } + + // Send to API with timeout + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + version := "2024-10-15" + params := &v20241015.CreateLogMessageParams{ + Version: version, + } + + resp, err := w.config.LdxSyncClient.CreateLogMessageWithResponse(ctx, params, requestBody) + if err != nil { + w.handleError(fmt.Errorf("failed to send logs: %w", err)) + return + } + + // Check response status + if resp.StatusCode() < 200 || resp.StatusCode() >= 300 { + w.handleError(fmt.Errorf("API returned non-success status: %d", resp.StatusCode())) + return + } +} + +// convertLogLevel converts zerolog.Level to the API log level +func convertLogLevel(level zerolog.Level) v20241015.LogMessageLevel { + switch level { + case zerolog.DebugLevel, zerolog.TraceLevel: + return v20241015.LogMessageLevelDebug + case zerolog.InfoLevel: + return v20241015.LogMessageLevelInfo + case zerolog.WarnLevel: + return v20241015.LogMessageLevelWarn + case zerolog.ErrorLevel, zerolog.FatalLevel, zerolog.PanicLevel: + return v20241015.LogMessageLevelError + default: + return v20241015.LogMessageLevelInfo + } +} + +// handleError calls the OnError callback if configured +func (w *APILogWriter) handleError(err error) { + if w.config.OnError != nil { + w.config.OnError(err) + } +} + +// Flush sends any remaining buffered logs to the API endpoint +func (w *APILogWriter) Flush() error { + w.mu.Lock() + bufferCopy := make([]LogEntry, len(w.buffer)) + copy(bufferCopy, w.buffer) + w.buffer = make([]LogEntry, 0) + w.currentBufferSize = 0 + w.mu.Unlock() + + if len(bufferCopy) > 0 { + w.sendLogs(bufferCopy) + } + + return nil +} + +// GetBufferSize returns the current buffer size in bytes +func (w *APILogWriter) GetBufferSize() int { + w.mu.RLock() + defer w.mu.RUnlock() + return w.currentBufferSize +} + +// GetBufferEntryCount returns the current number of entries in the buffer +func (w *APILogWriter) GetBufferEntryCount() int { + w.mu.RLock() + defer w.mu.RUnlock() + return len(w.buffer) +} + +// Clear removes all entries from the buffer +func (w *APILogWriter) Clear() { + w.mu.Lock() + defer w.mu.Unlock() + w.buffer = make([]LogEntry, 0) + w.currentBufferSize = 0 +} diff --git a/pkg/logging/apiLogWriter_test.go b/pkg/logging/apiLogWriter_test.go new file mode 100644 index 000000000..6a3b2ae6b --- /dev/null +++ b/pkg/logging/apiLogWriter_test.go @@ -0,0 +1,798 @@ +/* + * © 2025 Snyk Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package logging + +import ( + "context" + "fmt" + "net/http" + "sync" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + v20241015 "github.com/snyk/go-application-framework/pkg/apiclients/ldx_sync_config/ldx_sync/2024-10-15" + ldxmocks "github.com/snyk/go-application-framework/pkg/apiclients/ldx_sync_config/mocks" + "github.com/snyk/go-application-framework/pkg/logging/mocks" +) + +func TestNewAPILogWriter_DefaultValues(t *testing.T) { + config := APILogWriterConfig{} + + writer := NewAPILogWriter(config) + + assert.NotNil(t, writer) + assert.Equal(t, 10*1024*1024, writer.config.MaxBufferSize, "Should use default buffer size (10MB)") + assert.Equal(t, zerolog.ErrorLevel, writer.config.TriggerLevel, "Should use default trigger level") +} + +func TestNewAPILogWriter_CustomValues(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + config := APILogWriterConfig{ + MaxBufferSize: 100, + TriggerLevel: zerolog.WarnLevel, + LdxSyncClient: mockClient, + } + + writer := NewAPILogWriter(config) + + assert.NotNil(t, writer) + assert.Equal(t, 100, writer.config.MaxBufferSize) + assert.Equal(t, zerolog.WarnLevel, writer.config.TriggerLevel) + assert.Equal(t, mockClient, writer.config.LdxSyncClient) +} + +func TestAPILogWriter_BuffersMessages(t *testing.T) { + config := APILogWriterConfig{ + MaxBufferSize: 1024, // 1KB + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + // Write info level messages (below trigger level) + for i := 0; i < 5; i++ { + msg := fmt.Sprintf("log message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + // Check buffer has entries + assert.Equal(t, 5, writer.GetBufferEntryCount()) + assert.Greater(t, writer.GetBufferSize(), 0, "Buffer size should be greater than 0") +} + +func TestAPILogWriter_TrimsBufferWhenFull(t *testing.T) { + config := APILogWriterConfig{ + MaxBufferSize: 500, // 500 bytes + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + // Write more messages than the buffer can hold + for i := 0; i < 15; i++ { + msg := fmt.Sprintf("log message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + // Buffer size should be at or under max size + assert.LessOrEqual(t, writer.GetBufferSize(), config.MaxBufferSize) + + // Buffer should contain the most recent entries + writer.mu.RLock() + lastEntry := writer.buffer[len(writer.buffer)-1] + writer.mu.RUnlock() + assert.Contains(t, lastEntry.Message, "log message 14") +} + +func TestAPILogWriter_SendsOnTriggerLevel(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect CreateLogMessageWithResponse to be called with 4 log entries + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + // Verify we got 4 log messages (3 info + 1 error) + assert.Equal(t, 4, len(body.LogMessages)) + + // Create success response + response := &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{ + StatusCode: 201, + }, + } + return response, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Write some info messages + for i := 0; i < 3; i++ { + msg := fmt.Sprintf("info message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + // Write error message to trigger send + _, err := writer.WriteLevel(zerolog.ErrorLevel, []byte("error message")) + require.NoError(t, err) + + // Wait for async send + time.Sleep(100 * time.Millisecond) + + // Buffer should be cleared after send + assert.Equal(t, 0, writer.GetBufferSize()) +} + +func TestAPILogWriter_DoesNotSendBelowTriggerLevel(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect NO calls to CreateLogMessageWithResponse + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + Times(0) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + } + + writer := NewAPILogWriter(config) + + // Write only info and warn messages (below error level) + _, _ = writer.WriteLevel(zerolog.InfoLevel, []byte("info message")) + _, _ = writer.WriteLevel(zerolog.WarnLevel, []byte("warn message")) + + // Wait to ensure no async sends happened + time.Sleep(100 * time.Millisecond) + + // Buffer should still contain the messages + assert.Equal(t, 2, writer.GetBufferEntryCount()) +} + +func TestAPILogWriter_ThreadSafety(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect multiple calls (10 goroutines * 10 triggers each = ~100 calls) + // Use AnyTimes() since exact count is unpredictable with concurrency + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + AnyTimes() + + config := APILogWriterConfig{ + MaxBufferSize: 100 * 1024, // 100KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Run concurrent writes + var wg sync.WaitGroup + numGoroutines := 10 + writesPerGoroutine := 100 + + for i := 0; i < numGoroutines; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < writesPerGoroutine; j++ { + msg := fmt.Sprintf("message from goroutine %d: %d", id, j) + level := zerolog.InfoLevel + if j%10 == 0 { + level = zerolog.ErrorLevel // Trigger send occasionally + } + _, _ = writer.WriteLevel(level, []byte(msg)) + } + }(i) + } + + wg.Wait() + + // Test should complete without data races or panics + // Buffer size should be less than total writes due to triggered sends + assert.LessOrEqual(t, writer.GetBufferSize(), config.MaxBufferSize) +} + +func TestAPILogWriter_FlushSendsRemainingLogs(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect CreateLogMessageWithResponse to be called with 3 log entries + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + assert.Equal(t, 3, len(body.LogMessages)) + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Write info messages (won't trigger automatic send) + for i := 0; i < 3; i++ { + msg := fmt.Sprintf("info message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + assert.Equal(t, 3, writer.GetBufferEntryCount()) + + // Flush should send the logs + err := writer.Flush() + require.NoError(t, err) + + // Wait for async send + time.Sleep(100 * time.Millisecond) + + // Buffer should be empty + assert.Equal(t, 0, writer.GetBufferSize()) +} + +func TestAPILogWriter_ClearBuffer(t *testing.T) { + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + // Write some messages + for i := 0; i < 5; i++ { + msg := fmt.Sprintf("message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + assert.Equal(t, 5, writer.GetBufferEntryCount()) + + // Clear buffer + writer.Clear() + + assert.Equal(t, 0, writer.GetBufferSize()) +} + +func TestAPILogWriter_OnErrorCallback(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + var errorReceived error + var mu sync.Mutex + + // Expect CreateLogMessageWithResponse to return error status + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 500}, + }, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + OnError: func(err error) { + mu.Lock() + errorReceived = err + mu.Unlock() + }, + } + + writer := NewAPILogWriter(config) + + // Write error message to trigger send + _, err := writer.WriteLevel(zerolog.ErrorLevel, []byte("error message")) + require.NoError(t, err) + + // Wait for async send and error callback + time.Sleep(100 * time.Millisecond) + + // Check that error callback was called + mu.Lock() + defer mu.Unlock() + assert.NotNil(t, errorReceived) + assert.Contains(t, errorReceived.Error(), "non-success status") +} + +func TestAPILogWriter_WritesToUnderlyingWriter(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockWriter := mocks.NewMockLevelWriter(ctrl) + + messages := []string{"message 1", "message 2", "message 3"} + + // Expect WriteLevel to be called 3 times with the messages + for _, msg := range messages { + mockWriter.EXPECT(). + WriteLevel(zerolog.InfoLevel, []byte(msg)). + Return(len(msg), nil). + Times(1) + } + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + // Write messages + for _, msg := range messages { + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } +} + +func TestAPILogWriter_WriteMethod(t *testing.T) { + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + // Use Write method (should default to Info level) + msg := "test message" + n, err := writer.Write([]byte(msg)) + + require.NoError(t, err) + assert.Equal(t, len(msg), n) + assert.Equal(t, 1, writer.GetBufferEntryCount()) + + // Check that the entry has Info level + writer.mu.RLock() + entry := writer.buffer[0] + writer.mu.RUnlock() + assert.Equal(t, zerolog.InfoLevel, entry.Level) +} + +func TestAPILogWriter_LogEntryStructure(t *testing.T) { + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + } + + writer := NewAPILogWriter(config) + + msg := "test message" + beforeWrite := time.Now() + _, err := writer.WriteLevel(zerolog.WarnLevel, []byte(msg)) + afterWrite := time.Now() + + require.NoError(t, err) + + writer.mu.RLock() + entry := writer.buffer[0] + writer.mu.RUnlock() + + // Validate entry fields + assert.Equal(t, zerolog.WarnLevel, entry.Level) + assert.Equal(t, msg, entry.Message) + assert.True(t, entry.Timestamp.After(beforeWrite) || entry.Timestamp.Equal(beforeWrite)) + assert.True(t, entry.Timestamp.Before(afterWrite) || entry.Timestamp.Equal(afterWrite)) +} + +func TestAPILogWriter_NoClientDoesNotSend(t *testing.T) { + // No client configured + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: nil, // No client + } + + writer := NewAPILogWriter(config) + + // Write error message (would trigger send if client was set) + _, err := writer.WriteLevel(zerolog.ErrorLevel, []byte("error message")) + require.NoError(t, err) + + // Wait to ensure no panics occur + time.Sleep(100 * time.Millisecond) + + // Test should complete without errors + // Buffer should still contain the error message since it wasn't sent + assert.Equal(t, 0, writer.GetBufferSize()) // Buffer is cleared even without client +} + +func TestAPILogWriter_ConvertLevel(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect CreateLogMessageWithResponse to be called with 3 log entries + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + // Verify we got 3 log messages with correct level conversion + assert.Equal(t, 3, len(body.LogMessages)) + // Check levels were converted correctly + assert.Equal(t, v20241015.LogMessageLevelDebug, *body.LogMessages[0].Level) + assert.Equal(t, v20241015.LogMessageLevelInfo, *body.LogMessages[1].Level) + assert.Equal(t, v20241015.LogMessageLevelError, *body.LogMessages[2].Level) + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Write messages with different levels + _, _ = writer.WriteLevel(zerolog.DebugLevel, []byte("debug message")) + _, _ = writer.WriteLevel(zerolog.InfoLevel, []byte("info message")) + _, _ = writer.WriteLevel(zerolog.ErrorLevel, []byte("error message")) + + // Wait for async send + time.Sleep(100 * time.Millisecond) +} + +func TestAPILogWriter_BatchesBySize(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Track batches received + var batches []int + var mu sync.Mutex + + // Expect multiple calls due to batching + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + mu.Lock() + batches = append(batches, len(body.LogMessages)) + mu.Unlock() + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + AnyTimes() + + config := APILogWriterConfig{ + MaxBufferSize: 2 * 1024 * 1024, // 2MB buffer to hold all messages + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Create a large message that will force batching + // Each message is roughly 100KB, so 15 messages = ~1.5MB, requiring 2 batches + largeMessage := make([]byte, 100*1024) // 100KB + for i := range largeMessage { + largeMessage[i] = 'A' + } + + // Write 15 large messages + for i := 0; i < 15; i++ { + _, err := writer.WriteLevel(zerolog.InfoLevel, largeMessage) + require.NoError(t, err) + } + + // Trigger send with error level + _, err := writer.WriteLevel(zerolog.ErrorLevel, []byte("trigger")) + require.NoError(t, err) + + // Wait for async send + time.Sleep(200 * time.Millisecond) + + // Verify multiple batches were sent + mu.Lock() + defer mu.Unlock() + assert.Greater(t, len(batches), 1, "Should have sent multiple batches") + + // Verify total count matches + totalSent := 0 + for _, count := range batches { + totalSent += count + } + assert.Equal(t, 16, totalSent, "Should have sent all 16 messages (15 large + 1 trigger)") +} + +func TestAPILogWriter_SingleBatchUnder1MB(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect exactly one call with all entries (100 messages + 1 trigger = 101) + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + assert.Equal(t, 101, len(body.LogMessages), "Should send all entries in one batch (100 + trigger)") + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 100 * 1024, // 100KB - enough for all messages + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Write 100 small messages (well under 1MB total) + for i := 0; i < 100; i++ { + msg := fmt.Sprintf("small message %d", i) + _, err := writer.WriteLevel(zerolog.InfoLevel, []byte(msg)) + require.NoError(t, err) + } + + // Trigger send + _, err := writer.WriteLevel(zerolog.ErrorLevel, []byte("trigger")) + require.NoError(t, err) + + // Wait for async send + time.Sleep(100 * time.Millisecond) +} + +func TestAPILogWriter_OversizedSingleEntry(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + + // Expect call with normal message + trigger (oversized one gets trimmed from buffer before sending) + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + assert.Equal(t, 2, len(body.LogMessages), "Should send normal message and trigger (oversized trimmed)") + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + Times(1) + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024, // 10KB - small buffer to trim oversized message + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + + writer := NewAPILogWriter(config) + + // Try to write an oversized message (>1MB) + // This will be added to buffer then immediately trimmed because it exceeds MaxBufferSize + oversizedMessage := make([]byte, 2*1024*1024) // 2MB + for i := range oversizedMessage { + oversizedMessage[i] = 'X' + } + _, err := writer.WriteLevel(zerolog.InfoLevel, oversizedMessage) + require.NoError(t, err) + + // Write a normal message + _, err = writer.WriteLevel(zerolog.InfoLevel, []byte("normal message")) + require.NoError(t, err) + + // Trigger send + _, err = writer.WriteLevel(zerolog.ErrorLevel, []byte("trigger")) + require.NoError(t, err) + + // Wait for async send + time.Sleep(100 * time.Millisecond) + + // The oversized message was trimmed from the buffer, so only normal message and trigger are sent +} + +// Benchmark tests + +func BenchmarkAPILogWriter_WriteLevel(b *testing.B) { + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024 * 1024, // 10MB + TriggerLevel: zerolog.ErrorLevel, + } + writer := NewAPILogWriter(config) + msg := []byte("benchmark log message") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = writer.WriteLevel(zerolog.InfoLevel, msg) + } +} + +func BenchmarkAPILogWriter_WriteLevel_WithTrigger(b *testing.B) { + ctrl := gomock.NewController(b) + defer ctrl.Finish() + + mockClient := ldxmocks.NewMockClientWithResponsesInterface(ctrl) + mockClient.EXPECT(). + CreateLogMessageWithResponse(gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, params *v20241015.CreateLogMessageParams, body v20241015.CreateLogMessageJSONRequestBody, reqEditors ...v20241015.RequestEditorFn) (*v20241015.CreateLogMessageResponse, error) { + return &v20241015.CreateLogMessageResponse{ + HTTPResponse: &http.Response{StatusCode: 201}, + }, nil + }). + AnyTimes() + + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024 * 1024, // 10MB + TriggerLevel: zerolog.ErrorLevel, + LdxSyncClient: mockClient, + LogSource: v20241015.LogSource{}, + } + writer := NewAPILogWriter(config) + infoMsg := []byte("benchmark info message") + errorMsg := []byte("benchmark error message") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = writer.WriteLevel(zerolog.InfoLevel, infoMsg) + if i%100 == 0 { + _, _ = writer.WriteLevel(zerolog.ErrorLevel, errorMsg) + } + } +} + +func BenchmarkAPILogWriter_Batching(b *testing.B) { + entries := make([]LogEntry, 1000) + for i := 0; i < 1000; i++ { + entries[i] = LogEntry{ + Level: zerolog.InfoLevel, + Message: fmt.Sprintf("log message %d", i), + Timestamp: time.Now(), + } + } + + writer := &APILogWriter{ + config: APILogWriterConfig{ + MaxBufferSize: 10 * 1024 * 1024, + }, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = writer.batchEntriesBySize(entries) + } +} + +func BenchmarkAPILogWriter_ToAPIFormat(b *testing.B) { + batch := make(Batch, 100) + for i := 0; i < 100; i++ { + batch[i] = LogEntry{ + Level: zerolog.InfoLevel, + Message: fmt.Sprintf("log message %d", i), + Timestamp: time.Now(), + } + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = batch.toAPIFormat() + } +} + +func BenchmarkAPILogWriter_ConvertLevel(b *testing.B) { + levels := []zerolog.Level{ + zerolog.DebugLevel, + zerolog.InfoLevel, + zerolog.WarnLevel, + zerolog.ErrorLevel, + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = convertLogLevel(levels[i%len(levels)]) + } +} + +func BenchmarkAPILogWriter_ConcurrentWrites(b *testing.B) { + config := APILogWriterConfig{ + MaxBufferSize: 10 * 1024 * 1024, // 10MB + TriggerLevel: zerolog.ErrorLevel, + } + writer := NewAPILogWriter(config) + msg := []byte("concurrent benchmark log message") + + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _, _ = writer.WriteLevel(zerolog.InfoLevel, msg) + } + }) +} + +func BenchmarkAPILogWriter_BufferTrimming(b *testing.B) { + config := APILogWriterConfig{ + MaxBufferSize: 1024, // Small buffer to trigger trimming + TriggerLevel: zerolog.ErrorLevel, + } + writer := NewAPILogWriter(config) + msg := []byte("this is a log message that will cause buffer trimming") + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = writer.WriteLevel(zerolog.InfoLevel, msg) + } +} + +func BenchmarkLogEntry_ToJSON(b *testing.B) { + entry := LogEntry{ + Level: zerolog.InfoLevel, + Message: "benchmark log message", + Timestamp: time.Now(), + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _ = entry.toJSON() + } +} diff --git a/pkg/logging/mocks/zerolog_mock.go b/pkg/logging/mocks/zerolog_mock.go new file mode 100644 index 000000000..0aa21ba49 --- /dev/null +++ b/pkg/logging/mocks/zerolog_mock.go @@ -0,0 +1,65 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/rs/zerolog (interfaces: LevelWriter) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + zerolog "github.com/rs/zerolog" +) + +// MockLevelWriter is a mock of LevelWriter interface. +type MockLevelWriter struct { + ctrl *gomock.Controller + recorder *MockLevelWriterMockRecorder +} + +// MockLevelWriterMockRecorder is the mock recorder for MockLevelWriter. +type MockLevelWriterMockRecorder struct { + mock *MockLevelWriter +} + +// NewMockLevelWriter creates a new mock instance. +func NewMockLevelWriter(ctrl *gomock.Controller) *MockLevelWriter { + mock := &MockLevelWriter{ctrl: ctrl} + mock.recorder = &MockLevelWriterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLevelWriter) EXPECT() *MockLevelWriterMockRecorder { + return m.recorder +} + +// Write mocks base method. +func (m *MockLevelWriter) Write(arg0 []byte) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Write", arg0) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Write indicates an expected call of Write. +func (mr *MockLevelWriterMockRecorder) Write(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockLevelWriter)(nil).Write), arg0) +} + +// WriteLevel mocks base method. +func (m *MockLevelWriter) WriteLevel(arg0 zerolog.Level, arg1 []byte) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "WriteLevel", arg0, arg1) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// WriteLevel indicates an expected call of WriteLevel. +func (mr *MockLevelWriterMockRecorder) WriteLevel(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteLevel", reflect.TypeOf((*MockLevelWriter)(nil).WriteLevel), arg0, arg1) +} diff --git a/pkg/logging/mocks_generate.go b/pkg/logging/mocks_generate.go new file mode 100644 index 000000000..21d0a863e --- /dev/null +++ b/pkg/logging/mocks_generate.go @@ -0,0 +1,3 @@ +package logging + +//go:generate go tool github.com/golang/mock/mockgen -destination=mocks/zerolog_mock.go -package=mocks github.com/rs/zerolog LevelWriter