diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cef84b..cf8f245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Upcoming changes... +## [0.3.0] - 2023-11-27 +### Added +- Added SQL query tracing support + ## [0.2.0] - 2023-11-20 ### Added - Added Open Telemetry (OTEL) export support @@ -24,3 +28,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [0.1.0]: https://github.com/scanoss/go-grpc-helper/compare/v0.0.0...v0.1.0 [0.2.0]: https://github.com/scanoss/go-grpc-helper/compare/v0.1.0...v0.2.0 +[0.3.0]: https://github.com/scanoss/go-grpc-helper/compare/v0.2.0...v0.3.0 diff --git a/pkg/files/files.go b/pkg/files/files.go index 9fc6cc3..5d62568 100644 --- a/pkg/files/files.go +++ b/pkg/files/files.go @@ -21,6 +21,7 @@ * THE SOFTWARE. */ +// Package files provides some utilities for checking and loading files into memory package files import ( diff --git a/pkg/grpc/database/docs.go b/pkg/grpc/database/docs.go new file mode 100644 index 0000000..de88a4e --- /dev/null +++ b/pkg/grpc/database/docs.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2023, SCANOSS + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Package database contains functions to simplify opening/closing of DB connections, +// and tracing of SQL queries +package database diff --git a/pkg/grpc/database/queries.go b/pkg/grpc/database/queries.go new file mode 100644 index 0000000..f13dbdc --- /dev/null +++ b/pkg/grpc/database/queries.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2023, SCANOSS + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package database + +import ( + "context" + "regexp" + + "github.com/jmoiron/sqlx" + "go.uber.org/zap" +) + +var sqlRegex = regexp.MustCompile(`\$\d+`) // regex to check for SQL parameters + +type DBQueryContext struct { + conn *sqlx.Conn + s *zap.SugaredLogger + trace bool +} + +// NewDBSelectContext creates a new instance of the DBQueryContext service. +func NewDBSelectContext(s *zap.SugaredLogger, conn *sqlx.Conn, trace bool) *DBQueryContext { + return &DBQueryContext{s: s, conn: conn, trace: trace} +} + +// SelectContext logs the give query before executing it and the result afterward, if tracing is enabled? +func (q *DBQueryContext) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error { + if q.trace { + q.SQLQueryTrace(query, args...) + } + err := q.conn.SelectContext(ctx, dest, query, args...) + if err == nil && q.trace { + q.SQLResultsTrace(dest) + } + return err +} + +// SQLQueryTrace logs the given SQL query if debug is enabled. +func (q *DBQueryContext) SQLQueryTrace(query string, args ...interface{}) { + q.s.Debugf("SQL Query: "+sqlRegex.ReplaceAllString(query, "%v"), args...) +} + +// SQLResultsTrace logs the given SQL result if debug is enabled. +func (q *DBQueryContext) SQLResultsTrace(results interface{}) { + q.s.Debugf("SQL Results: %#v", results) +} diff --git a/pkg/grpc/database/queries_test.go b/pkg/grpc/database/queries_test.go new file mode 100644 index 0000000..99b69ae --- /dev/null +++ b/pkg/grpc/database/queries_test.go @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (c) 2023, SCANOSS + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package database + +import ( + "fmt" + "testing" + + "golang.org/x/net/context" + + _ "github.com/lib/pq" + _ "github.com/mattn/go-sqlite3" + zlog "github.com/scanoss/zap-logging-helper/pkg/logger" +) + +type Persons struct { + FirstName string + LastName string +} + +func TestQuerySQLite(t *testing.T) { + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) + } + defer zlog.SyncZap() + db, err := OpenDBConnection(":memory:", "sqlite3", "", "", "", "", "") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + defer CloseDBConnection(db) + db.MustExec("CREATE TABLE person (firstname text, lastname text)") + db.MustExec("INSERT INTO person (firstname, lastname) VALUES ('harry', 'potter')") + ctx := context.Background() + conn, err := db.Connx(ctx) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + q := NewDBSelectContext(zlog.S, conn, true) + var results []Persons + err = q.SelectContext(ctx, &results, "SELECT * FROM person where firstname = $1", "harry") + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + fmt.Printf("Results: %v\n", results) +}