Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code structure Refactoring #162

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3b5a535
Added support for Query Row and Query Context
Thiyagu55 Sep 19, 2022
f9b7cad
Added support for http-router
Thiyagu55 Sep 22, 2022
0cc3b08
Go-SQL Implementation done
Thiyagu55 Sep 23, 2022
373142d
Added README.md & copyright header
Thiyagu55 Sep 23, 2022
d61b985
Updated net/http
Thiyagu55 Sep 23, 2022
f89b7b3
Update README.md
sjs994 Sep 23, 2022
dc6c518
Update go-sql.go
sjs994 Sep 23, 2022
f7eb636
Added support for otel traceparet
Thiyagu55 Sep 26, 2022
935870f
PR changes for otel integration
Thiyagu55 Sep 27, 2022
5ac9c42
Added Unittests
Thiyagu55 Sep 27, 2022
5ff4995
PR changes
Thiyagu55 Sep 27, 2022
1ef9f62
PR changes
Thiyagu55 Sep 28, 2022
f79cf94
Added CI unittest pipeline
Thiyagu55 Sep 28, 2022
3327a3b
Added CI unittest pipeline
Thiyagu55 Sep 28, 2022
9749f6b
Added sqlmock module
Thiyagu55 Sep 28, 2022
4b5cebc
Added CI unittest pipeline
Thiyagu55 Sep 28, 2022
c347efb
Added gofmt tests
Thiyagu55 Sep 28, 2022
f27540a
Added gofmt tests
Thiyagu55 Sep 28, 2022
50e7ffd
Rename Package
Thiyagu55 Sep 28, 2022
6ce058a
updated github workflow
Thiyagu55 Sep 28, 2022
50aff88
updated github workflow
Thiyagu55 Sep 28, 2022
266ff1e
renamed github workflow
Thiyagu55 Sep 29, 2022
ec74286
Code structure refactoring
Thiyagu55 Sep 30, 2022
c328bbb
Merge branch 'go-sql-implementation' of https://github.com/Thiyagu55/…
Thiyagu55 Sep 30, 2022
2968a73
PR changes
Thiyagu55 Sep 30, 2022
cdb2c15
PR changes
Thiyagu55 Sep 30, 2022
fd5c508
PR changes
Thiyagu55 Sep 30, 2022
72278f4
PR changes
Thiyagu55 Sep 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
php/sqlcommenter-php/packages/sqlcommenter-laravel/vendor/*
.idea/**
.idea/**
**/.vscode/**
28 changes: 28 additions & 0 deletions go/core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# SQLCommenter Core [In development]

SQLcommenter is a plugin/middleware/wrapper to augment application related information/tags with SQL Statements that can be used later to correlate user code with SQL statements.

This package contains configuration options, framework interface and support functions for all the sqlcommenter go modules

## Installation

This is a support package and will be installed indirectly by other go sqlcommenter packages

## Usages

### Configuration

Users are given control over what tags they want to append by using `core.CommenterOptions` struct.

```go
type CommenterOptions struct {
EnableDBDriver bool
EnableTraceparent bool // OpenTelemetry trace information
EnableRoute bool // applicable for web frameworks
EnableFramework bool // applicable for web frameworks
EnableController bool // applicable for web frameworks
EnableAction bool // applicable for web frameworks
}
```


90 changes: 90 additions & 0 deletions go/core/core.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2022 Google LLC
//
// 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 core

import (
"context"
"fmt"
"net/url"
"reflect"
"runtime"
"sort"
"strings"

"go.opentelemetry.io/otel/propagation"
)

const (
Route string = "route"
Controller string = "controller"
Action string = "action"
Framework string = "framework"
Driver string = "driver"
Traceparent string = "traceparent"
)

type CommenterOptions struct {
EnableDBDriver bool
EnableRoute bool
EnableFramework bool
EnableController bool
EnableAction bool
EnableTraceparent bool
}

func encodeURL(k string) string {
return url.QueryEscape(string(k))
}

func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

func ConvertMapToComment(tags map[string]string) string {
var sb strings.Builder
i, sz := 0, len(tags)

//sort by keys
sortedKeys := make([]string, 0, len(tags))
for k := range tags {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)

for _, key := range sortedKeys {
if i == sz-1 {
sb.WriteString(fmt.Sprintf("%s=%v", encodeURL(key), encodeURL(tags[key])))
} else {
sb.WriteString(fmt.Sprintf("%s=%v,", encodeURL(key), encodeURL(tags[key])))
}
i++
}
return sb.String()
}

func ExtractTraceparent(ctx context.Context) propagation.MapCarrier {
// Serialize the context into carrier
propgator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
carrier := propagation.MapCarrier{}
propgator.Inject(ctx, carrier)
return carrier
}

type RequestTagger interface {
Route() string
Action() string
Framework() string
GetContext() context.Context
}
7 changes: 7 additions & 0 deletions go/core/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module google.com/sqlcommenter/core

go 1.19

require go.opentelemetry.io/otel v1.10.0

require go.opentelemetry.io/otel/trace v1.10.0 // indirect
11 changes: 11 additions & 0 deletions go/core/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
go.opentelemetry.io/otel v1.10.0 h1:Y7DTJMR6zs1xkS/upamJYk0SxxN4C9AqRd77jmZnyY4=
go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ=
go.opentelemetry.io/otel/trace v1.10.0 h1:npQMbR8o7mum8uF95yFbOEJffhs1sbCOfDh8zAJiH5E=
go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
46 changes: 15 additions & 31 deletions go/go-sql/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Sqlcommenter [In development]
# go-sql-driver [In development]

SQLcommenter is a plugin/middleware/wrapper to augment application related information/tags with SQL Statements that can be used later to correlate user code with SQL statements.

Expand All @@ -7,28 +7,29 @@ SQLcommenter is a plugin/middleware/wrapper to augment application related infor
### Install from source

* Clone the source
* In terminal go inside the client folder location where we need to import google-sqlcommenter package and enter the below commands
* In terminal go inside the client folder location where we need to import sqlcommenter go-sql module and enter the below commands

```shell
go mod edit -replace google.com/sqlcommenter=path/to/google/sqlcommenter/go
go mod edit -replace google.com/sqlcommenter=path/to/google/sqlcommenter/go-sql

go mod tiny

go get google.com/sqlcommenter/gosql
```
### Install from github [To be added]

## Usages
## Usage

### go-sql-driver
Please use the sqlcommenter's default database driver to execute statements. \
Please use the sqlcommenter's default go-sql database driver to execute statements.
Due to inherent nature of Go, the safer way to pass information from framework to database driver is via `context`. So, it is recommended to use the context based methods of `DB` interface like `QueryContext`, `ExecContext` and `PrepareContext`.

```go
db, err := sqlcommenter.Open("<driver>", "<connectionString>", sqlcommenter.CommenterOptions{<tag>:<bool>})
db, err := gosql.Open("<driver>", "<connectionString>", sqlcommenter.CommenterOptions{<tag>:<bool>})
```

#### Configuration
### Configuration

Users are given control over what tags they want to append by using `sqlcommenter.CommenterOptions` struct.
Users are given control over what tags they want to append by using `core.CommenterOptions` struct.

```go
type CommenterOptions struct {
Expand All @@ -41,32 +42,15 @@ type CommenterOptions struct {
}
```

### net/http
Populate the request context with sqlcommenter.AddHttpRouterTags(r) function in a custom middleware.

#### Note
* We only support the `database/sql` driver and have provided an implementation for that.
* <b>ORM related tags are added to the driver only when the tags are enabled in the commenter's driver's config and also the request context should passed to the querying functions</b>
### Framework Supported
* [http/net](.../../../http-net/README.md)

#### Example
```go
// middleware is used to intercept incoming HTTP calls and populate request context with commenter tags.
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := sqlcommenter.AddHttpRouterTags(r, next)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
```

## Options

With Go SqlCommenter, we have configuration to choose which tags to be appended to the comment.

| Options | Included by default? | go-sql-orm | net/http | Notes |
| --------------- | :------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---: |
| `DBDriver` | | [ go-sql-driver](https://pkg.go.dev/database/sql/driver) | |
| `Action` | | | [net/http handle](https://pkg.go.dev/net/http#Handle) | |
| `Route` | | | [net/http routing path](https://pkg.go.dev/github.com/gorilla/mux#Route.URLPath) | |
| `Framework` | | | [net/http](https://pkg.go.dev/net/http) | |
| `Opentelemetry` | | [W3C TraceContext.Traceparent](https://www.w3.org/TR/trace-context/#traceparent-field), [W3C TraceContext.Tracestate](https://www.w3.org/TR/trace-context/#tracestate-field) | [W3C TraceContext.Traceparent](https://www.w3.org/TR/trace-context/#traceparent-field), [W3C TraceContext.Tracestate](https://www.w3.org/TR/trace-context/#tracestate-field) | |
| Options | Included by default? | go-sql-driver |
| ---------- | -------------------- | -------------------------------------------------------- |
| `DBDriver` | | [ go-sql-driver](https://pkg.go.dev/database/sql/driver) |
103 changes: 13 additions & 90 deletions go/go-sql/go-sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,40 +18,17 @@ import (
"context"
"database/sql"
"fmt"
"net/http"
"net/url"
"reflect"
"runtime"
"sort"
"strings"

"go.opentelemetry.io/otel/propagation"
)

const (
route string = "route"
controller string = "controller"
action string = "action"
framework string = "framework"
driver string = "driver"
traceparent string = "traceparent"
"google.com/sqlcommenter/core"
)

type DB struct {
*sql.DB
options CommenterOptions
}

type CommenterOptions struct {
EnableDBDriver bool
EnableRoute bool
EnableFramework bool
EnableController bool
EnableAction bool
EnableTraceparent bool
options core.CommenterOptions
}

func Open(driverName string, dataSourceName string, options CommenterOptions) (*DB, error) {
func Open(driverName string, dataSourceName string, options core.CommenterOptions) (*DB, error) {
db, err := sql.Open(driverName, dataSourceName)
return &DB{DB: db, options: options}, err
}
Expand Down Expand Up @@ -88,53 +65,41 @@ func (db *DB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, erro

// ***** Query Functions *****

// ***** Framework Functions *****

func AddHttpRouterTags(r *http.Request, next any) context.Context { // any type is set because we need to refrain from importing http-router package
ctx := context.Background()
ctx = context.WithValue(ctx, route, r.URL.Path)
ctx = context.WithValue(ctx, action, getFunctionName(next))
ctx = context.WithValue(ctx, framework, "net/http")
return ctx
}

// ***** Framework Functions *****

// ***** Commenter Functions *****

func (db *DB) withComment(ctx context.Context, query string) string {
var commentsMap = map[string]string{}
query = strings.TrimSpace(query)

// Sorted alphabetically
if db.options.EnableAction && (ctx.Value(action) != nil) {
commentsMap[action] = ctx.Value(action).(string)
if db.options.EnableAction && (ctx.Value(core.Action) != nil) {
commentsMap[core.Action] = ctx.Value(core.Action).(string)
}

// `driver` information should not be coming from framework.
// So, explicitly adding that here.
if db.options.EnableDBDriver {
commentsMap[driver] = "database/sql"
commentsMap[core.Driver] = "database/sql"
}

if db.options.EnableFramework && (ctx.Value(framework) != nil) {
commentsMap[framework] = ctx.Value(framework).(string)
if db.options.EnableFramework && (ctx.Value(core.Framework) != nil) {
commentsMap[core.Framework] = ctx.Value(core.Framework).(string)
}

if db.options.EnableRoute && (ctx.Value(route) != nil) {
commentsMap[route] = ctx.Value(route).(string)
if db.options.EnableRoute && (ctx.Value(core.Route) != nil) {
commentsMap[core.Route] = ctx.Value(core.Route).(string)
}

if db.options.EnableTraceparent {
carrier := extractTraceparent(ctx)
carrier := core.ExtractTraceparent(ctx)
if val, ok := carrier["traceparent"]; ok {
commentsMap[traceparent] = val
commentsMap[core.Traceparent] = val
}
}

var commentsString string = ""
if len(commentsMap) > 0 { // Converts comments map to string and appends it to query
commentsString = fmt.Sprintf("/*%s*/", convertMapToComment(commentsMap))
commentsString = fmt.Sprintf("/*%s*/", core.ConvertMapToComment(commentsMap))
}

// A semicolon at the end of the SQL statement means the query ends there.
Expand All @@ -146,45 +111,3 @@ func (db *DB) withComment(ctx context.Context, query string) string {
}

// ***** Commenter Functions *****

// ***** Util Functions *****

func encodeURL(k string) string {
return url.QueryEscape(string(k))
}

func getFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}

func convertMapToComment(tags map[string]string) string {
var sb strings.Builder
i, sz := 0, len(tags)

//sort by keys
sortedKeys := make([]string, 0, len(tags))
for k := range tags {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)

for _, key := range sortedKeys {
if i == sz-1 {
sb.WriteString(fmt.Sprintf("%s=%v", encodeURL(key), encodeURL(tags[key])))
} else {
sb.WriteString(fmt.Sprintf("%s=%v,", encodeURL(key), encodeURL(tags[key])))
}
i++
}
return sb.String()
}

func extractTraceparent(ctx context.Context) propagation.MapCarrier {
// Serialize the context into carrier
propgator := propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})
carrier := propagation.MapCarrier{}
propgator.Inject(ctx, carrier)
return carrier
}

// ***** Util Functions *****
Loading