mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
chore: implement diagnostics endpoint (resolve #225)
This commit is contained in:
parent
9e3203ac41
commit
2088987a0c
@ -33,6 +33,7 @@ const (
|
||||
SimpleDateTimeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
ErrUnauthorized = "401 unauthorized"
|
||||
ErrBadRequest = "400 bad request"
|
||||
ErrInternalServerError = "500 internal server error"
|
||||
)
|
||||
|
||||
@ -203,6 +204,9 @@ func (c *Config) GetMigrationFunc(dbDialect string) models.MigrationFunc {
|
||||
if err := db.AutoMigrate(&models.ProjectLabel{}); err != nil && !c.Db.AutoMigrateFailSilently {
|
||||
return err
|
||||
}
|
||||
if err := db.AutoMigrate(&models.Diagnostics{}); err != nil && !c.Db.AutoMigrateFailSilently {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
6
main.go
6
main.go
@ -54,6 +54,7 @@ var (
|
||||
projectLabelRepository repositories.IProjectLabelRepository
|
||||
summaryRepository repositories.ISummaryRepository
|
||||
keyValueRepository repositories.IKeyValueRepository
|
||||
diagnosticsRepository repositories.IDiagnosticsRepository
|
||||
)
|
||||
|
||||
var (
|
||||
@ -67,6 +68,7 @@ var (
|
||||
mailService services.IMailService
|
||||
keyValueService services.IKeyValueService
|
||||
reportService services.IReportService
|
||||
diagnosticsService services.IDiagnosticsService
|
||||
miscService services.IMiscService
|
||||
)
|
||||
|
||||
@ -143,6 +145,7 @@ func main() {
|
||||
projectLabelRepository = repositories.NewProjectLabelRepository(db)
|
||||
summaryRepository = repositories.NewSummaryRepository(db)
|
||||
keyValueRepository = repositories.NewKeyValueRepository(db)
|
||||
diagnosticsRepository = repositories.NewDiagnosticsRepository(db)
|
||||
|
||||
// Services
|
||||
mailService = mail.NewMailService()
|
||||
@ -155,6 +158,7 @@ func main() {
|
||||
aggregationService = services.NewAggregationService(userService, summaryService, heartbeatService)
|
||||
keyValueService = services.NewKeyValueService(keyValueRepository)
|
||||
reportService = services.NewReportService(summaryService, userService, mailService)
|
||||
diagnosticsService = services.NewDiagnosticsService(diagnosticsRepository)
|
||||
miscService = services.NewMiscService(userService, summaryService, keyValueService)
|
||||
|
||||
// Schedule background tasks
|
||||
@ -169,6 +173,7 @@ func main() {
|
||||
heartbeatApiHandler := api.NewHeartbeatApiHandler(userService, heartbeatService, languageMappingService)
|
||||
summaryApiHandler := api.NewSummaryApiHandler(userService, summaryService)
|
||||
metricsHandler := api.NewMetricsHandler(userService, summaryService, heartbeatService, keyValueService)
|
||||
diagnosticsHandler := api.NewDiagnosticsApiHandler(userService, diagnosticsService)
|
||||
|
||||
// Compat Handlers
|
||||
wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(userService, summaryService)
|
||||
@ -219,6 +224,7 @@ func main() {
|
||||
healthApiHandler.RegisterRoutes(apiRouter)
|
||||
heartbeatApiHandler.RegisterRoutes(apiRouter)
|
||||
metricsHandler.RegisterRoutes(apiRouter)
|
||||
diagnosticsHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1AllHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1SummariesHandler.RegisterRoutes(apiRouter)
|
||||
wakatimeV1StatsHandler.RegisterRoutes(apiRouter)
|
||||
|
13
models/diagnostics.go
Normal file
13
models/diagnostics.go
Normal file
@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
type Diagnostics struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
User *User `json:"-" gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
UserID string `json:"-" gorm:"not null; index:idx_diagnostics_user"`
|
||||
Platform string `json:"platform"`
|
||||
Architecture string `json:"architecture"`
|
||||
Plugin string `json:"plugin"`
|
||||
CliVersion string `json:"cli_version"`
|
||||
Logs string `json:"logs" gorm:"type:text"`
|
||||
StackTrace string `json:"stacktrace" gorm:"type:text"`
|
||||
}
|
18
repositories/diagnostics.go
Normal file
18
repositories/diagnostics.go
Normal file
@ -0,0 +1,18 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DiagnosticsRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewDiagnosticsRepository(db *gorm.DB) *DiagnosticsRepository {
|
||||
return &DiagnosticsRepository{db: db}
|
||||
}
|
||||
|
||||
func (r *DiagnosticsRepository) Insert(diagnostics *models.Diagnostics) (*models.Diagnostics, error) {
|
||||
return diagnostics, r.db.Create(diagnostics).Error
|
||||
}
|
@ -31,6 +31,10 @@ type IHeartbeatRepository interface {
|
||||
DeleteBefore(time.Time) error
|
||||
}
|
||||
|
||||
type IDiagnosticsRepository interface {
|
||||
Insert(diagnostics *models.Diagnostics) (*models.Diagnostics, error)
|
||||
}
|
||||
|
||||
type IKeyValueRepository interface {
|
||||
GetAll() ([]*models.KeyStringValue, error)
|
||||
GetString(string) (*models.KeyStringValue, error)
|
||||
|
71
routes/api/diagnostics.go
Normal file
71
routes/api/diagnostics.go
Normal file
@ -0,0 +1,71 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gorilla/mux"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"net/http"
|
||||
|
||||
"github.com/muety/wakapi/models"
|
||||
)
|
||||
|
||||
type DiagnosticsApiHandler struct {
|
||||
config *conf.Config
|
||||
userSrvc services.IUserService
|
||||
diagnosticsSrvc services.IDiagnosticsService
|
||||
}
|
||||
|
||||
func NewDiagnosticsApiHandler(userService services.IUserService, diagnosticsService services.IDiagnosticsService) *DiagnosticsApiHandler {
|
||||
return &DiagnosticsApiHandler{
|
||||
config: conf.Get(),
|
||||
userSrvc: userService,
|
||||
diagnosticsSrvc: diagnosticsService,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *DiagnosticsApiHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("/plugins/errors").Subrouter()
|
||||
r.Use(
|
||||
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||
)
|
||||
r.Path("").Methods(http.MethodPost).HandlerFunc(h.Post)
|
||||
}
|
||||
|
||||
// @Summary Push a new diagnostics object
|
||||
// @ID post-diagnostics
|
||||
// @Tags diagnostics
|
||||
// @Accept json
|
||||
// @Param diagnostics body models.Diagnostics true "A single diagnostics object sent by WakaTime CLI"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 201
|
||||
// @Router /plugins/errors [post]
|
||||
func (h *DiagnosticsApiHandler) Post(w http.ResponseWriter, r *http.Request) {
|
||||
var diagnostics models.Diagnostics
|
||||
|
||||
user := middlewares.GetPrincipal(r)
|
||||
if user == nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
w.Write([]byte(conf.ErrUnauthorized))
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&diagnostics); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(conf.ErrBadRequest))
|
||||
conf.Log().Request(r).Error("failed to parse diagnostics for user %s - %v", err)
|
||||
return
|
||||
}
|
||||
diagnostics.UserID = user.ID
|
||||
|
||||
if _, err := h.diagnosticsSrvc.Create(&diagnostics); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(conf.ErrInternalServerError))
|
||||
conf.Log().Request(r).Error("failed to insert diagnostics for user %s - %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
utils.RespondJSON(w, r, http.StatusCreated, struct{}{})
|
||||
}
|
@ -72,6 +72,7 @@ func (h *HeartbeatApiHandler) Post(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
heartbeats, err = h.tryParseSingle(r)
|
||||
if err != nil {
|
||||
conf.Log().Request(r).Error(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
|
23
services/diagnostics.go
Normal file
23
services/diagnostics.go
Normal file
@ -0,0 +1,23 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/repositories"
|
||||
)
|
||||
|
||||
type DiagnosticsService struct {
|
||||
config *config.Config
|
||||
repository repositories.IDiagnosticsRepository
|
||||
}
|
||||
|
||||
func NewDiagnosticsService(diagnosticsRepo repositories.IDiagnosticsRepository) *DiagnosticsService {
|
||||
return &DiagnosticsService{
|
||||
config: config.Get(),
|
||||
repository: diagnosticsRepo,
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *DiagnosticsService) Create(diagnostics *models.Diagnostics) (*models.Diagnostics, error) {
|
||||
return srv.repository.Insert(diagnostics)
|
||||
}
|
@ -39,6 +39,10 @@ type IHeartbeatService interface {
|
||||
DeleteBefore(time.Time) error
|
||||
}
|
||||
|
||||
type IDiagnosticsService interface {
|
||||
Create(*models.Diagnostics) (*models.Diagnostics, error)
|
||||
}
|
||||
|
||||
type IKeyValueService interface {
|
||||
GetString(string) (*models.KeyStringValue, error)
|
||||
MustGetString(string) *models.KeyStringValue
|
||||
|
@ -482,6 +482,39 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/errors": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"diagnostics"
|
||||
],
|
||||
"summary": "Push a new diagnostics object",
|
||||
"operationId": "post-diagnostics",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "A single diagnostics object sent by WakaTime CLI",
|
||||
"name": "diagnostics",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Diagnostics"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/summary": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -687,6 +720,32 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"models.Diagnostics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "string"
|
||||
},
|
||||
"cli_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"logs": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"plugin": {
|
||||
"type": "string"
|
||||
},
|
||||
"stacktrace": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Heartbeat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -750,6 +809,7 @@ var doc = `{
|
||||
"example": "2006-01-02 15:04:05.000"
|
||||
},
|
||||
"labels": {
|
||||
"description": "labels are not persisted, but calculated at runtime, i.e. when summary is retrieved",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.SummaryItem"
|
||||
|
@ -466,6 +466,39 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/plugins/errors": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"diagnostics"
|
||||
],
|
||||
"summary": "Push a new diagnostics object",
|
||||
"operationId": "post-diagnostics",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "A single diagnostics object sent by WakaTime CLI",
|
||||
"name": "diagnostics",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.Diagnostics"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/summary": {
|
||||
"get": {
|
||||
"security": [
|
||||
@ -671,6 +704,32 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"models.Diagnostics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "string"
|
||||
},
|
||||
"cli_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"logs": {
|
||||
"type": "string"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"plugin": {
|
||||
"type": "string"
|
||||
},
|
||||
"stacktrace": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Heartbeat": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -734,6 +793,7 @@
|
||||
"example": "2006-01-02 15:04:05.000"
|
||||
},
|
||||
"labels": {
|
||||
"description": "labels are not persisted, but calculated at runtime, i.e. when summary is retrieved",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.SummaryItem"
|
||||
|
@ -1,5 +1,22 @@
|
||||
basePath: /api
|
||||
definitions:
|
||||
models.Diagnostics:
|
||||
properties:
|
||||
architecture:
|
||||
type: string
|
||||
cli_version:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
logs:
|
||||
type: string
|
||||
platform:
|
||||
type: string
|
||||
plugin:
|
||||
type: string
|
||||
stacktrace:
|
||||
type: string
|
||||
type: object
|
||||
models.Heartbeat:
|
||||
properties:
|
||||
branch:
|
||||
@ -44,6 +61,8 @@ definitions:
|
||||
format: date
|
||||
type: string
|
||||
labels:
|
||||
description: labels are not persisted, but calculated at runtime, i.e. when
|
||||
summary is retrieved
|
||||
items:
|
||||
$ref: '#/definitions/models.SummaryItem'
|
||||
type: array
|
||||
@ -622,6 +641,26 @@ paths:
|
||||
summary: Push new heartbeats
|
||||
tags:
|
||||
- heartbeat
|
||||
/plugins/errors:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
operationId: post-diagnostics
|
||||
parameters:
|
||||
- description: A single diagnostics object sent by WakaTime CLI
|
||||
in: body
|
||||
name: diagnostics
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.Diagnostics'
|
||||
responses:
|
||||
"201":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Push a new diagnostics object
|
||||
tags:
|
||||
- diagnostics
|
||||
/summary:
|
||||
get:
|
||||
operationId: get-summary
|
||||
|
Loading…
Reference in New Issue
Block a user