This repository was archived by the owner on Oct 8, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/store processed stats in pgsql database #12
Open
c1-ra
wants to merge
17
commits into
main
Choose a base branch
from
feat/store-processed-stats-in-pgsql-database
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
c96859d
Add service with connection to database
ac89531
Add `benchttp.stats.go` with necessary structs to interact with database
5218040
Add `postgresql.stats.go` with `Create()` method
e5492e6
Add `insertIntoTimestats` statement in `Create()`
815f7cf
Add `ErrExecutingRollback` error
f949585
Change statement names
fc3bef7
Add new lines
009132f
Remove custom errors
fb03af5
Fix `if err` multiple conditions to not override errors
af7e19c
Remove `.env` file
ac31012
Change service name to `InsertionService`
f919ba3
Change StatsService to InsertionService
b09d274
Create a new InsertionService in main.go
bcde53e
Add codestats insertion
035836a
Add buildStats() method, call NewInsertService() in main.go
c865578
Add documentation comments
0ff18d6
feat: get id from report in firestore
moreirathomas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| # Editor settings | ||
| .vscode/ | ||
|
|
||
| # Env files | ||
| .env | ||
|
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package benchttp | ||
|
|
||
| // InsertService defines the interface to implement by a | ||
| // data layer facade. | ||
| type InsertionService interface { | ||
| // Create stores stats in database. | ||
| Insert(Stats) error | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package benchttp | ||
|
|
||
| import ( | ||
| "time" | ||
|
|
||
| "github.com/benchttp/worker/stats" | ||
| ) | ||
|
|
||
| // StatsDescriptor contains a computed stats group description information. | ||
| type StatsDescriptor struct { | ||
| ID string `json:"id"` | ||
| UserID string `json:"userID"` | ||
| Tag string `json:"tag"` | ||
| FinishedAt time.Time `json:"finishedAt"` | ||
| } | ||
|
|
||
| // Stats contains StatsDescriptor, Codestats and stats.Stats of a given computed stats group. | ||
| type Stats struct { | ||
| Descriptor StatsDescriptor `json:"descriptor"` | ||
| Code stats.StatusDistribution `json:"code"` | ||
| Time stats.Common `json:"time"` | ||
| } | ||
|
|
||
| // Config contains the information needed to connect to the database | ||
| // and set max idle connections and open connections number. | ||
| type Config struct { | ||
| Host string | ||
| User string | ||
| Password string | ||
| DBName string | ||
| IdleConn int | ||
| MaxConn int | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,22 +2,37 @@ package worker | |||||||||||||
|
|
||||||||||||||
| import ( | ||||||||||||||
| "context" | ||||||||||||||
| "errors" | ||||||||||||||
| "log" | ||||||||||||||
| "os" | ||||||||||||||
| "time" | ||||||||||||||
|
|
||||||||||||||
| "github.com/googleapis/google-cloudevents-go/cloud/firestore/v1" | ||||||||||||||
|
|
||||||||||||||
| "github.com/benchttp/worker/benchttp" | ||||||||||||||
| "github.com/benchttp/worker/firestoreconv" | ||||||||||||||
| "github.com/benchttp/worker/postgresql" | ||||||||||||||
| "github.com/benchttp/worker/stats" | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| // Digest is a Cloud Function triggered by a Firestore create document | ||||||||||||||
| // event to extract, compute and store statistics of a Benchttp run. | ||||||||||||||
| // It also stores the computed data in a SQL database. | ||||||||||||||
|
Comment on lines
18
to
+20
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| func Digest(ctx context.Context, e firestore.DocumentEventData) error { | ||||||||||||||
| r, err := firestoreconv.Report(e.Value) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| cfg, err := envConfig() | ||||||||||||||
| if err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
| insertionService, err := postgresql.NewInsertionService(cfg) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| codes, times := r.Benchmark.Values() | ||||||||||||||
|
|
||||||||||||||
| timestats, err := stats.ComputeCommon(times) | ||||||||||||||
|
|
@@ -34,5 +49,56 @@ func Digest(ctx context.Context, e firestore.DocumentEventData) error { | |||||||||||||
|
|
||||||||||||||
| log.Printf("codestats: %+v", codestats) | ||||||||||||||
|
|
||||||||||||||
| // TO DO: get user id. Using "1" here for the moment. | ||||||||||||||
| statsToInsert := buildStats(timestats, codestats, "firestore_id", "1") | ||||||||||||||
|
|
||||||||||||||
| if err := insertionService.Insert(statsToInsert); err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return nil | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func envConfig() (benchttp.Config, error) { | ||||||||||||||
| var config benchttp.Config | ||||||||||||||
|
|
||||||||||||||
| config.Host = os.Getenv("PSQL_HOST") | ||||||||||||||
| if config.Host == "" { | ||||||||||||||
| return config, errors.New("PSQL_HOST environment variable not found") | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| config.User = os.Getenv("PSQL_USER") | ||||||||||||||
| if config.User == "" { | ||||||||||||||
| return config, errors.New("PSQL_USER environment variable not found") | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| config.Password = os.Getenv("PSQL_PASSWORD") | ||||||||||||||
| if config.Password == "" { | ||||||||||||||
| return config, errors.New("PSQL_PASSWORD environment variable not found") | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| config.DBName = os.Getenv("PSQL_NAME") | ||||||||||||||
| if config.DBName == "" { | ||||||||||||||
| return config, errors.New("PSQL_NAME environment variable not found") | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| config.IdleConn = 10 | ||||||||||||||
| config.MaxConn = 25 | ||||||||||||||
|
|
||||||||||||||
| return config, nil | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // buildStats builds a benchttp.Stats object. | ||||||||||||||
| // Descriptor.FinishedAt is set at time.now(). | ||||||||||||||
| func buildStats(timestats stats.Common, codestats stats.StatusDistribution, reportID, userID string) benchttp.Stats { | ||||||||||||||
| computedstats := benchttp.Stats{ | ||||||||||||||
| Descriptor: benchttp.StatsDescriptor{ | ||||||||||||||
| ID: reportID, | ||||||||||||||
| UserID: userID, | ||||||||||||||
| FinishedAt: time.Now(), | ||||||||||||||
| }, | ||||||||||||||
| Time: timestats, | ||||||||||||||
| Code: codestats, | ||||||||||||||
| } | ||||||||||||||
| return computedstats | ||||||||||||||
| } | ||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package postgresql | ||
|
|
||
| import ( | ||
| "database/sql" | ||
| "fmt" | ||
|
|
||
| _ "github.com/GoogleCloudPlatform/cloudsql-proxy/proxy/dialers/postgres" // blank import | ||
|
|
||
| "github.com/benchttp/worker/benchttp" | ||
| ) | ||
|
|
||
| // InsertionService implements benchttp.InsertionService interface. | ||
| type InsertionService struct { | ||
| db *sql.DB | ||
| } | ||
|
|
||
| // NewInsertionService connects to the database and provides an InsertionService | ||
| // implementing benchttp.InsertionService, which provides a method to insert | ||
| // data in database. | ||
| func NewInsertionService(config benchttp.Config) (InsertionService, error) { | ||
| dbURI := fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable", | ||
| config.Host, | ||
| config.User, | ||
| config.Password, | ||
| config.DBName) | ||
|
|
||
| db, err := sql.Open("cloudsqlpostgres", dbURI) | ||
| if err != nil { | ||
| return InsertionService{}, err | ||
| } | ||
|
|
||
| err = db.Ping() | ||
| if err != nil { | ||
| return InsertionService{}, err | ||
| } | ||
|
|
||
| db.SetMaxIdleConns(config.IdleConn) | ||
| db.SetMaxOpenConns(config.MaxConn) | ||
|
|
||
| return InsertionService{db}, nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| package postgresql | ||
|
|
||
| import ( | ||
| "github.com/lib/pq" | ||
|
|
||
| "github.com/benchttp/worker/benchttp" | ||
| ) | ||
|
|
||
| // Insert inserts computed stats (benchttp.Stats) in the database. | ||
| // nolint:gocognit | ||
| func (s InsertionService) Insert(stats benchttp.Stats) error { | ||
| tx, err := s.db.Begin() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| insertStatsDescriptor, err := tx.Prepare(` | ||
| INSERT INTO public.stats_descriptor( | ||
| id, | ||
| user_id, | ||
| finished_at) | ||
| VALUES($1, $2, $3)`) | ||
| if err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
| defer insertStatsDescriptor.Close() | ||
|
|
||
| if _, err = insertStatsDescriptor.Exec( | ||
| stats.Descriptor.ID, | ||
| stats.Descriptor.UserID, | ||
| stats.Descriptor.FinishedAt, | ||
| ); err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| insertTimestats, err := tx.Prepare(` | ||
| INSERT INTO public.timestats( | ||
| stats_descriptor_id, | ||
| min, | ||
| max, | ||
| mean, | ||
| median, | ||
| standard_deviation, | ||
| deciles) | ||
| VALUES($1, $2, $3, $4, $5, $6, $7)`) | ||
| if err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
| defer insertTimestats.Close() | ||
|
|
||
| if _, err = insertTimestats.Exec( | ||
| stats.Descriptor.ID, | ||
| stats.Time.Min, | ||
| stats.Time.Max, | ||
| stats.Time.Mean, | ||
| stats.Time.Median, | ||
| stats.Time.StdDev, | ||
| pq.Array(stats.Time.Deciles), | ||
| ); err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| insertCodestats, err := tx.Prepare(` | ||
| INSERT INTO codestats( | ||
| stats_descriptor_id, | ||
| code_1xx, | ||
| code_2xx, | ||
| code_3xx, | ||
| code_4xx, | ||
| code_5xx | ||
| ) VALUES($1, $2, $3, $4, $5, $6)`) | ||
| if err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
| defer insertCodestats.Close() | ||
|
|
||
| if _, err = insertCodestats.Exec( | ||
| stats.Descriptor.ID, | ||
| stats.Code.Status1xx, | ||
| stats.Code.Status2xx, | ||
| stats.Code.Status3xx, | ||
| stats.Code.Status4xx, | ||
| stats.Code.Status5xx, | ||
| ); err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
|
|
||
| err = tx.Commit() | ||
| if err != nil { | ||
| if err := tx.Rollback(); err != nil { | ||
| return err | ||
| } | ||
| return err | ||
| } | ||
| return nil | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Configof postgresql db does not belong tobenchttppackage I think.Simply move it to
postegresqland we're fine :)