Compare commits
2 Commits
v3.11.44
...
816abc2bbc
| Author | SHA1 | Date | |
|---|---|---|---|
| 816abc2bbc | |||
| f3f2a9b737 |
@@ -3,16 +3,14 @@ name: coverage
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main, v3, v4 ]
|
branches: [ main, v3, v4 ]
|
||||||
paths-ignore:
|
|
||||||
- '.github/**'
|
|
||||||
- '.gitea/**'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main, v3, v4 ]
|
branches: [ main, v3, v4 ]
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
if: github.server_url != 'https://github.com'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
@@ -41,8 +39,8 @@ jobs:
|
|||||||
name: autocommit
|
name: autocommit
|
||||||
with:
|
with:
|
||||||
commit_message: Apply Code Coverage Badge
|
commit_message: Apply Code Coverage Badge
|
||||||
skip_fetch: false
|
skip_fetch: true
|
||||||
skip_checkout: false
|
skip_checkout: true
|
||||||
file_pattern: ./README.md
|
file_pattern: ./README.md
|
||||||
|
|
||||||
- name: push
|
- name: push
|
||||||
@@ -3,10 +3,10 @@ name: lint
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
branches: [ master, v3, v4 ]
|
branches:
|
||||||
paths-ignore:
|
- master
|
||||||
- '.github/**'
|
- v3
|
||||||
- '.gitea/**'
|
- v4
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
@@ -24,6 +24,6 @@ jobs:
|
|||||||
- name: setup deps
|
- name: setup deps
|
||||||
run: go get -v ./...
|
run: go get -v ./...
|
||||||
- name: run lint
|
- name: run lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: https://github.com/golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
version: 'latest'
|
version: 'latest'
|
||||||
@@ -3,12 +3,15 @@ name: test
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
branches: [ master, v3, v4 ]
|
branches:
|
||||||
|
- master
|
||||||
|
- v3
|
||||||
|
- v4
|
||||||
push:
|
push:
|
||||||
branches: [ master, v3, v4 ]
|
branches:
|
||||||
paths-ignore:
|
- master
|
||||||
- '.github/**'
|
- v3
|
||||||
- '.gitea/**'
|
- v4
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
@@ -3,12 +3,15 @@ name: test
|
|||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
branches: [ master, v3, v4 ]
|
branches:
|
||||||
|
- master
|
||||||
|
- v3
|
||||||
|
- v4
|
||||||
push:
|
push:
|
||||||
branches: [ master, v3, v4 ]
|
branches:
|
||||||
paths-ignore:
|
- master
|
||||||
- '.github/**'
|
- v3
|
||||||
- '.gitea/**'
|
- v4
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
@@ -32,19 +35,19 @@ jobs:
|
|||||||
go-version: 'stable'
|
go-version: 'stable'
|
||||||
- name: setup go work
|
- name: setup go work
|
||||||
env:
|
env:
|
||||||
GOWORK: ${{ github.workspace }}/go.work
|
GOWORK: /workspace/${{ github.repository_owner }}/go.work
|
||||||
run: |
|
run: |
|
||||||
go work init
|
go work init
|
||||||
go work use .
|
go work use .
|
||||||
go work use micro-tests
|
go work use micro-tests
|
||||||
- name: setup deps
|
- name: setup deps
|
||||||
env:
|
env:
|
||||||
GOWORK: ${{ github.workspace }}/go.work
|
GOWORK: /workspace/${{ github.repository_owner }}/go.work
|
||||||
run: go get -v ./...
|
run: go get -v ./...
|
||||||
- name: run tests
|
- name: run tests
|
||||||
env:
|
env:
|
||||||
INTEGRATION_TESTS: yes
|
INTEGRATION_TESTS: yes
|
||||||
GOWORK: ${{ github.workspace }}/go.work
|
GOWORK: /workspace/${{ github.repository_owner }}/go.work
|
||||||
run: |
|
run: |
|
||||||
cd micro-tests
|
cd micro-tests
|
||||||
go test -mod readonly -v ./... || true
|
go test -mod readonly -v ./... || true
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
run:
|
run:
|
||||||
concurrency: 8
|
concurrency: 8
|
||||||
timeout: 5m
|
deadline: 5m
|
||||||
issues-exit-code: 1
|
issues-exit-code: 1
|
||||||
tests: true
|
tests: true
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,5 +1,5 @@
|
|||||||
# Micro
|
# Micro
|
||||||

|

|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://pkg.go.dev/go.unistack.org/micro/v3?tab=overview)
|
[](https://pkg.go.dev/go.unistack.org/micro/v3?tab=overview)
|
||||||
[](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av3+event%3Apush)
|
[](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av3+event%3Apush)
|
||||||
@@ -9,20 +9,20 @@ Micro is a standard library for microservices.
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Micro provides the core requirements for distributed systems development including SYNC and ASYNC communication.
|
Micro provides the core requirements for distributed systems development including RPC and Event driven communication.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
Micro abstracts away the details of distributed systems. Main features:
|
Micro abstracts away the details of distributed systems. Here are the main features.
|
||||||
|
|
||||||
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
|
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
|
||||||
level config from any source such as env vars, cmdline, file, consul, vault, etc... You can merge the sources and even define fallbacks.
|
level config from any source such as env vars, cmdline, file, consul, vault... You can merge the sources and even define fallbacks.
|
||||||
|
|
||||||
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
|
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
|
||||||
s3. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
|
s3. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
|
||||||
|
|
||||||
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
|
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
|
||||||
development.
|
development. When service A needs to speak to service B it needs the location of that service.
|
||||||
|
|
||||||
- **Message Encoding** - Dynamic message encoding based on content-type. The client and server will use codecs along with content-type
|
- **Message Encoding** - Dynamic message encoding based on content-type. The client and server will use codecs along with content-type
|
||||||
to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client
|
to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client
|
||||||
|
|||||||
15
SECURITY.md
Normal file
15
SECURITY.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 3.7.x | :white_check_mark: |
|
||||||
|
| < 3.7.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you find any issue, please create github issue in this repo
|
||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultBroker default memory broker
|
// DefaultBroker default memory broker
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
maddr "go.unistack.org/micro/v3/util/addr"
|
maddr "go.unistack.org/micro/v4/util/addr"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
mnet "go.unistack.org/micro/v3/util/net"
|
mnet "go.unistack.org/micro/v4/util/net"
|
||||||
"go.unistack.org/micro/v3/util/rand"
|
"go.unistack.org/micro/v4/util/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memoryBroker struct {
|
type memoryBroker struct {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMemoryBatchBroker(t *testing.T) {
|
func TestMemoryBatchBroker(t *testing.T) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NoopBroker struct {
|
type NoopBroker struct {
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/sync"
|
"go.unistack.org/micro/v4/sync"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options struct
|
// Options struct
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/util/backoff"
|
"go.unistack.org/micro/v4/util/backoff"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackoffFunc is the backoff call func
|
// BackoffFunc is the backoff call func
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LookupFunc is used to lookup routes for a service
|
// LookupFunc is used to lookup routes for a service
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
"go.unistack.org/micro/v3/semconv"
|
"go.unistack.org/micro/v4/semconv"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultCodecs will be used to encode/decode data
|
// DefaultCodecs will be used to encode/decode data
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
"go.unistack.org/micro/v3/selector/random"
|
"go.unistack.org/micro/v4/selector/random"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options holds client options
|
// Options holds client options
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package client
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RetryFunc that returning either false or a non-nil error will result in the call not being retried
|
// RetryFunc that returning either false or a non-nil error will result in the call not being retried
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRetryAlways(t *testing.T) {
|
func TestRetryAlways(t *testing.T) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testRequest struct {
|
type testRequest struct {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package cluster
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message sent to member in cluster
|
// Message sent to member in cluster
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package codec
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
|
|
||||||
"dario.cat/mergo"
|
"dario.cat/mergo"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
mid "go.unistack.org/micro/v3/util/id"
|
mid "go.unistack.org/micro/v4/util/id"
|
||||||
rutil "go.unistack.org/micro/v3/util/reflect"
|
rutil "go.unistack.org/micro/v4/util/reflect"
|
||||||
mtime "go.unistack.org/micro/v3/util/time"
|
mtime "go.unistack.org/micro/v4/util/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type defaultConfig struct {
|
type defaultConfig struct {
|
||||||
@@ -210,7 +210,7 @@ func fillValue(value reflect.Value, val string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
value.Set(reflect.ValueOf(v))
|
value.Set(reflect.ValueOf(v))
|
||||||
case value.Type().String() == "time.Duration" && value.Type().PkgPath() == "go.unistack.org/micro/v3/util/time":
|
case value.Type().String() == "time.Duration" && value.Type().PkgPath() == "go.unistack.org/micro/v4/util/time":
|
||||||
v, err := mtime.ParseDuration(val)
|
v, err := mtime.ParseDuration(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/config"
|
"go.unistack.org/micro/v4/config"
|
||||||
mtime "go.unistack.org/micro/v3/util/time"
|
mtime "go.unistack.org/micro/v4/util/time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type cfg struct {
|
type cfg struct {
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options hold the config options
|
// Options hold the config options
|
||||||
|
|||||||
2
event.go
2
event.go
@@ -3,7 +3,7 @@ package micro
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event is used to publish messages to a topic
|
// Event is used to publish messages to a topic
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/silas/dag"
|
"github.com/silas/dag"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/store"
|
"go.unistack.org/micro/v4/store"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
type microFlow struct {
|
type microFlow struct {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/store"
|
"go.unistack.org/micro/v4/store"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFSMStart(t *testing.T) {
|
func TestFSMStart(t *testing.T) {
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -1,22 +1,21 @@
|
|||||||
module go.unistack.org/micro/v3
|
module go.unistack.org/micro/v4
|
||||||
|
|
||||||
go 1.22.0
|
go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
dario.cat/mergo v1.0.1
|
dario.cat/mergo v1.0.1
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.2
|
github.com/DATA-DOG/go-sqlmock v1.5.2
|
||||||
github.com/KimMachineGun/automemlimit v0.6.1
|
github.com/KimMachineGun/automemlimit v0.7.0
|
||||||
github.com/ash3in/uuidv8 v1.2.0
|
github.com/ash3in/uuidv8 v1.2.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/matoous/go-nanoid v1.5.1
|
github.com/matoous/go-nanoid v1.5.1
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
|
github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5
|
||||||
github.com/stretchr/testify v1.10.0
|
|
||||||
go.uber.org/automaxprocs v1.6.0
|
go.uber.org/automaxprocs v1.6.0
|
||||||
go.unistack.org/micro-proto/v3 v3.4.1
|
go.unistack.org/micro-proto/v3 v3.4.1
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.10.0
|
||||||
google.golang.org/grpc v1.69.2
|
google.golang.org/grpc v1.69.4
|
||||||
google.golang.org/protobuf v1.36.1
|
google.golang.org/protobuf v1.36.3
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -34,10 +33,11 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
go.uber.org/goleak v1.3.0 // indirect
|
go.uber.org/goleak v1.3.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||||
golang.org/x/net v0.33.0 // indirect
|
golang.org/x/net v0.34.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
package metadata
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
|
||||||
"go.unistack.org/micro/v3/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
var DefaultMetadataKeys = []string{"x-request-id"}
|
|
||||||
|
|
||||||
type hook struct {
|
|
||||||
keys []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHook(keys ...string) *hook {
|
|
||||||
return &hook{keys: keys}
|
|
||||||
}
|
|
||||||
|
|
||||||
func metadataCopy(ctx context.Context, keys []string) context.Context {
|
|
||||||
if keys == nil {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
if imd, iok := metadata.FromIncomingContext(ctx); iok && imd != nil {
|
|
||||||
omd, ook := metadata.FromOutgoingContext(ctx)
|
|
||||||
if !ook || omd == nil {
|
|
||||||
omd = metadata.New(len(keys))
|
|
||||||
}
|
|
||||||
for _, k := range keys {
|
|
||||||
if v, ok := imd.Get(k); ok && v != "" {
|
|
||||||
omd.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !ook {
|
|
||||||
ctx = metadata.NewOutgoingContext(ctx, omd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientCall(next client.FuncCall) client.FuncCall {
|
|
||||||
return func(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
|
||||||
return next(metadataCopy(ctx, w.keys), req, rsp, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientStream(next client.FuncStream) client.FuncStream {
|
|
||||||
return func(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
|
||||||
return next(metadataCopy(ctx, w.keys), req, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientPublish(next client.FuncPublish) client.FuncPublish {
|
|
||||||
return func(ctx context.Context, msg client.Message, opts ...client.PublishOption) error {
|
|
||||||
return next(metadataCopy(ctx, w.keys), msg, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientBatchPublish(next client.FuncBatchPublish) client.FuncBatchPublish {
|
|
||||||
return func(ctx context.Context, msgs []client.Message, opts ...client.PublishOption) error {
|
|
||||||
return next(metadataCopy(ctx, w.keys), msgs, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerHandler(next server.FuncHandler) server.FuncHandler {
|
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
|
||||||
return next(metadataCopy(ctx, w.keys), req, rsp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerSubscriber(next server.FuncSubHandler) server.FuncSubHandler {
|
|
||||||
return func(ctx context.Context, msg server.Message) error {
|
|
||||||
return next(metadataCopy(ctx, w.keys), msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package recovery
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
|
||||||
"go.unistack.org/micro/v3/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewOptions(opts ...Option) Options {
|
|
||||||
options := Options{
|
|
||||||
ServerHandlerFn: DefaultServerHandlerFn,
|
|
||||||
ServerSubscriberFn: DefaultServerSubscriberFn,
|
|
||||||
}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&options)
|
|
||||||
}
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
type Options struct {
|
|
||||||
ServerHandlerFn func(context.Context, server.Request, interface{}, error) error
|
|
||||||
ServerSubscriberFn func(context.Context, server.Message, error) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Option func(*Options)
|
|
||||||
|
|
||||||
func ServerHandlerFunc(fn func(context.Context, server.Request, interface{}, error) error) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ServerHandlerFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServerSubscriberFunc(fn func(context.Context, server.Message, error) error) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ServerSubscriberFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultServerHandlerFn = func(ctx context.Context, req server.Request, rsp interface{}, err error) error {
|
|
||||||
return errors.BadRequest("", "%v", err)
|
|
||||||
}
|
|
||||||
DefaultServerSubscriberFn = func(ctx context.Context, req server.Message, err error) error {
|
|
||||||
return errors.BadRequest("", "%v", err)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var Hook = NewHook()
|
|
||||||
|
|
||||||
type hook struct {
|
|
||||||
opts Options
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHook(opts ...Option) *hook {
|
|
||||||
return &hook{opts: NewOptions(opts...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerHandler(next server.FuncHandler) server.FuncHandler {
|
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) (err error) {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
switch verr := r.(type) {
|
|
||||||
case nil:
|
|
||||||
return
|
|
||||||
case error:
|
|
||||||
err = w.opts.ServerHandlerFn(ctx, req, rsp, verr)
|
|
||||||
default:
|
|
||||||
err = w.opts.ServerHandlerFn(ctx, req, rsp, fmt.Errorf("%v", r))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err = next(ctx, req, rsp)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerSubscriber(next server.FuncSubHandler) server.FuncSubHandler {
|
|
||||||
return func(ctx context.Context, msg server.Message) (err error) {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
switch verr := r.(type) {
|
|
||||||
case nil:
|
|
||||||
return
|
|
||||||
case error:
|
|
||||||
err = w.opts.ServerSubscriberFn(ctx, msg, verr)
|
|
||||||
default:
|
|
||||||
err = w.opts.ServerSubscriberFn(ctx, msg, fmt.Errorf("%v", r))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err = next(ctx, msg)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
package requestid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/textproto"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
|
||||||
"go.unistack.org/micro/v3/server"
|
|
||||||
"go.unistack.org/micro/v3/util/id"
|
|
||||||
)
|
|
||||||
|
|
||||||
type XRequestIDKey struct{}
|
|
||||||
|
|
||||||
// DefaultMetadataKey contains metadata key
|
|
||||||
var DefaultMetadataKey = textproto.CanonicalMIMEHeaderKey("x-request-id")
|
|
||||||
|
|
||||||
// DefaultMetadataFunc wil be used if user not provide own func to fill metadata
|
|
||||||
var DefaultMetadataFunc = func(ctx context.Context) (context.Context, error) {
|
|
||||||
var xid string
|
|
||||||
|
|
||||||
cid, cok := ctx.Value(XRequestIDKey{}).(string)
|
|
||||||
if cok && cid != "" {
|
|
||||||
xid = cid
|
|
||||||
}
|
|
||||||
|
|
||||||
imd, iok := metadata.FromIncomingContext(ctx)
|
|
||||||
if !iok || imd == nil {
|
|
||||||
imd = metadata.New(1)
|
|
||||||
ctx = metadata.NewIncomingContext(ctx, imd)
|
|
||||||
}
|
|
||||||
|
|
||||||
omd, ook := metadata.FromOutgoingContext(ctx)
|
|
||||||
if !ook || omd == nil {
|
|
||||||
omd = metadata.New(1)
|
|
||||||
ctx = metadata.NewOutgoingContext(ctx, omd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if xid == "" {
|
|
||||||
var id string
|
|
||||||
if id, iok = imd.Get(DefaultMetadataKey); iok && id != "" {
|
|
||||||
xid = id
|
|
||||||
}
|
|
||||||
if id, ook = omd.Get(DefaultMetadataKey); ook && id != "" {
|
|
||||||
xid = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if xid == "" {
|
|
||||||
var err error
|
|
||||||
xid, err = id.New()
|
|
||||||
if err != nil {
|
|
||||||
return ctx, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cok {
|
|
||||||
ctx = context.WithValue(ctx, XRequestIDKey{}, xid)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !iok {
|
|
||||||
imd.Set(DefaultMetadataKey, xid)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ook {
|
|
||||||
omd.Set(DefaultMetadataKey, xid)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type hook struct{}
|
|
||||||
|
|
||||||
func NewHook() *hook {
|
|
||||||
return &hook{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerSubscriber(next server.FuncSubHandler) server.FuncSubHandler {
|
|
||||||
return func(ctx context.Context, msg server.Message) error {
|
|
||||||
var err error
|
|
||||||
if xid, ok := msg.Header()[DefaultMetadataKey]; ok {
|
|
||||||
ctx = context.WithValue(ctx, XRequestIDKey{}, xid)
|
|
||||||
}
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return next(ctx, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerHandler(next server.FuncHandler) server.FuncHandler {
|
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
|
||||||
var err error
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return next(ctx, req, rsp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientBatchPublish(next client.FuncBatchPublish) client.FuncBatchPublish {
|
|
||||||
return func(ctx context.Context, msgs []client.Message, opts ...client.PublishOption) error {
|
|
||||||
var err error
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return next(ctx, msgs, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientPublish(next client.FuncPublish) client.FuncPublish {
|
|
||||||
return func(ctx context.Context, msg client.Message, opts ...client.PublishOption) error {
|
|
||||||
var err error
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return next(ctx, msg, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientCall(next client.FuncCall) client.FuncCall {
|
|
||||||
return func(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
|
||||||
var err error
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return next(ctx, req, rsp, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientStream(next client.FuncStream) client.FuncStream {
|
|
||||||
return func(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
|
||||||
var err error
|
|
||||||
if ctx, err = DefaultMetadataFunc(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return next(ctx, req, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package requestid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDefaultMetadataFunc(t *testing.T) {
|
|
||||||
ctx := context.TODO()
|
|
||||||
|
|
||||||
nctx, err := DefaultMetadataFunc(ctx)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
imd, ok := metadata.FromIncomingContext(nctx)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("md missing in incoming context")
|
|
||||||
}
|
|
||||||
omd, ok := metadata.FromOutgoingContext(nctx)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("md missing in outgoing context")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, iok := imd.Get(DefaultMetadataKey)
|
|
||||||
_, ook := omd.Get(DefaultMetadataKey)
|
|
||||||
|
|
||||||
if !iok || !ook {
|
|
||||||
t.Fatalf("missing metadata key value")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql/driver"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:generate sh -c "go run gen.go > wrap_gen.go"
|
|
||||||
|
|
||||||
// namedValueToValue converts driver arguments of NamedValue format to Value format. Implemented in the same way as in
|
|
||||||
// database/sql ctxutil.go.
|
|
||||||
func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
|
|
||||||
dargs := make([]driver.Value, len(named))
|
|
||||||
for n, param := range named {
|
|
||||||
if len(param.Name) > 0 {
|
|
||||||
return nil, errors.New("sql: driver does not support the use of Named Parameters")
|
|
||||||
}
|
|
||||||
dargs[n] = param.Value
|
|
||||||
}
|
|
||||||
return dargs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// namedValueToLabels convert driver arguments to interface{} slice
|
|
||||||
func namedValueToLabels(named []driver.NamedValue) []interface{} {
|
|
||||||
largs := make([]interface{}, 0, len(named)*2)
|
|
||||||
var name string
|
|
||||||
for _, param := range named {
|
|
||||||
if param.Name != "" {
|
|
||||||
name = param.Name
|
|
||||||
} else {
|
|
||||||
name = fmt.Sprintf("$%d", param.Ordinal)
|
|
||||||
}
|
|
||||||
largs = append(largs, fmt.Sprintf("%s=%v", name, param.Value))
|
|
||||||
}
|
|
||||||
return largs
|
|
||||||
}
|
|
||||||
|
|
||||||
// getCallerName get the name of the function A where A() -> B() -> GetFunctionCallerName()
|
|
||||||
func getCallerName() string {
|
|
||||||
pc, _, _, ok := runtime.Caller(3)
|
|
||||||
details := runtime.FuncForPC(pc)
|
|
||||||
var callerName string
|
|
||||||
if ok && details != nil {
|
|
||||||
callerName = details.Name()
|
|
||||||
} else {
|
|
||||||
callerName = labelUnknown
|
|
||||||
}
|
|
||||||
return callerName
|
|
||||||
}
|
|
||||||
@@ -1,467 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql/driver"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/hooks/requestid"
|
|
||||||
"go.unistack.org/micro/v3/tracer"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ driver.Conn = (*wrapperConn)(nil)
|
|
||||||
_ driver.ConnBeginTx = (*wrapperConn)(nil)
|
|
||||||
_ driver.ConnPrepareContext = (*wrapperConn)(nil)
|
|
||||||
_ driver.Pinger = (*wrapperConn)(nil)
|
|
||||||
_ driver.Validator = (*wrapperConn)(nil)
|
|
||||||
_ driver.Queryer = (*wrapperConn)(nil) // nolint:staticcheck
|
|
||||||
_ driver.QueryerContext = (*wrapperConn)(nil)
|
|
||||||
_ driver.Execer = (*wrapperConn)(nil) // nolint:staticcheck
|
|
||||||
_ driver.ExecerContext = (*wrapperConn)(nil)
|
|
||||||
// _ driver.Connector
|
|
||||||
// _ driver.Driver
|
|
||||||
// _ driver.DriverContext
|
|
||||||
)
|
|
||||||
|
|
||||||
// wrapperConn defines a wrapper for driver.Conn
|
|
||||||
type wrapperConn struct {
|
|
||||||
d *wrapperDriver
|
|
||||||
dname string
|
|
||||||
conn driver.Conn
|
|
||||||
opts Options
|
|
||||||
ctx context.Context
|
|
||||||
//span tracer.Span
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements driver.Conn Close
|
|
||||||
func (w *wrapperConn) Close() error {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Close"}
|
|
||||||
ts := time.Now()
|
|
||||||
err := w.conn.Close()
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Close", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin implements driver.Conn Begin
|
|
||||||
func (w *wrapperConn) Begin() (driver.Tx, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
|
|
||||||
labels := []string{labelMethod, "Begin"}
|
|
||||||
ts := time.Now()
|
|
||||||
tx, err := w.conn.Begin() // nolint:staticcheck
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Begin", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Begin", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return &wrapperTx{tx: tx, opts: w.opts, ctx: ctx}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeginTx implements driver.ConnBeginTx BeginTx
|
|
||||||
func (w *wrapperConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
nctx, span := w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
span.AddLabels("db.method", "BeginTx")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "BeginTx", labelQuery, name}
|
|
||||||
|
|
||||||
connBeginTx, ok := w.conn.(driver.ConnBeginTx)
|
|
||||||
if !ok {
|
|
||||||
return w.Begin()
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
tx, err := connBeginTx.BeginTx(nctx, opts)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "BeginTx", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "BeginTx", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return &wrapperTx{tx: tx, opts: w.opts, ctx: ctx, span: span}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare implements driver.Conn Prepare
|
|
||||||
func (w *wrapperConn) Prepare(query string) (driver.Stmt, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Prepare", labelQuery, getCallerName()}
|
|
||||||
ts := time.Now()
|
|
||||||
stmt, err := w.conn.Prepare(query)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Prepare", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Prepare", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return wrapStmt(stmt, query, w.opts), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrepareContext implements driver.ConnPrepareContext PrepareContext
|
|
||||||
func (w *wrapperConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
|
|
||||||
var nctx context.Context
|
|
||||||
var span tracer.Span
|
|
||||||
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "PrepareContext")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "PrepareContext", labelQuery, name}
|
|
||||||
conn, ok := w.conn.(driver.ConnPrepareContext)
|
|
||||||
if !ok {
|
|
||||||
return w.Prepare(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
stmt, err := conn.PrepareContext(nctx, query)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "PrepareContext", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "PrepareContext", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return wrapStmt(stmt, query, w.opts), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec implements driver.Execer Exec
|
|
||||||
func (w *wrapperConn) Exec(query string, args []driver.Value) (driver.Result, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Exec", labelQuery, getCallerName()}
|
|
||||||
|
|
||||||
// nolint:staticcheck
|
|
||||||
conn, ok := w.conn.(driver.Execer)
|
|
||||||
if !ok {
|
|
||||||
return nil, driver.ErrSkip
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
res, err := conn.Exec(query, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Exec", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec implements driver.StmtExecContext ExecContext
|
|
||||||
func (w *wrapperConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
|
|
||||||
var nctx context.Context
|
|
||||||
var span tracer.Span
|
|
||||||
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "ExecContext")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
defer span.Finish()
|
|
||||||
if len(args) > 0 {
|
|
||||||
span.AddLabels("db.args", fmt.Sprintf("%v", namedValueToLabels(args)))
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "ExecContext", labelQuery, name}
|
|
||||||
|
|
||||||
conn, ok := w.conn.(driver.ExecerContext)
|
|
||||||
if !ok {
|
|
||||||
// nolint:staticcheck
|
|
||||||
return nil, driver.ErrSkip
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
res, err := conn.ExecContext(nctx, query, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "ExecContext", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ping implements driver.Pinger Ping
|
|
||||||
func (w *wrapperConn) Ping(ctx context.Context) error {
|
|
||||||
conn, ok := w.conn.(driver.Pinger)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
// fallback path to check db alive
|
|
||||||
pc, err := w.d.Open(w.dname)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return pc.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
var nctx context.Context //nolint: gosimple
|
|
||||||
nctx = ctx
|
|
||||||
/*
|
|
||||||
var span tracer.Span
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "Ping")
|
|
||||||
defer span.Finish()
|
|
||||||
*/
|
|
||||||
labels := []string{labelMethod, "Ping"}
|
|
||||||
ts := time.Now()
|
|
||||||
err := conn.Ping(nctx)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
// span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Ping", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query implements driver.Queryer Query
|
|
||||||
func (w *wrapperConn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
// nolint:staticcheck
|
|
||||||
conn, ok := w.conn.(driver.Queryer)
|
|
||||||
if !ok {
|
|
||||||
return nil, driver.ErrSkip
|
|
||||||
}
|
|
||||||
|
|
||||||
labels := []string{labelMethod, "Query", labelQuery, getCallerName()}
|
|
||||||
ts := time.Now()
|
|
||||||
rows, err := conn.Query(query, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Query", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return rows, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryContext implements Driver.QueryerContext QueryContext
|
|
||||||
func (w *wrapperConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
|
||||||
var nctx context.Context
|
|
||||||
var span tracer.Span
|
|
||||||
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "QueryContext")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
defer span.Finish()
|
|
||||||
if len(args) > 0 {
|
|
||||||
span.AddLabels("db.args", fmt.Sprintf("%v", namedValueToLabels(args)))
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "QueryContext", labelQuery, name}
|
|
||||||
conn, ok := w.conn.(driver.QueryerContext)
|
|
||||||
if !ok {
|
|
||||||
return nil, driver.ErrSkip
|
|
||||||
}
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
rows, err := conn.QueryContext(nctx, query, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "QueryContext", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return rows, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckNamedValue implements driver.NamedValueChecker
|
|
||||||
func (w *wrapperConn) CheckNamedValue(v *driver.NamedValue) error {
|
|
||||||
s, ok := w.conn.(driver.NamedValueChecker)
|
|
||||||
if !ok {
|
|
||||||
return driver.ErrSkip
|
|
||||||
}
|
|
||||||
return s.CheckNamedValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValid implements driver.Validator
|
|
||||||
func (w *wrapperConn) IsValid() bool {
|
|
||||||
v, ok := w.conn.(driver.Validator)
|
|
||||||
if !ok {
|
|
||||||
return w.conn != nil
|
|
||||||
}
|
|
||||||
return v.IsValid()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *wrapperConn) ResetSession(ctx context.Context) error {
|
|
||||||
s, ok := w.conn.(driver.SessionResetter)
|
|
||||||
if !ok {
|
|
||||||
return driver.ErrSkip
|
|
||||||
}
|
|
||||||
return s.ResetSession(ctx)
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql/driver"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// _ driver.DriverContext = (*wrapperDriver)(nil)
|
|
||||||
// _ driver.Connector = (*wrapperDriver)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
type conn interface {
|
|
||||||
driver.Pinger
|
|
||||||
driver.Execer
|
|
||||||
driver.ExecerContext
|
|
||||||
driver.Queryer
|
|
||||||
driver.QueryerContext
|
|
||||||
driver.Conn
|
|
||||||
driver.ConnPrepareContext
|
|
||||||
driver.ConnBeginTx
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// wrapperDriver defines a wrapper for driver.Driver
|
|
||||||
type wrapperDriver struct {
|
|
||||||
driver driver.Driver
|
|
||||||
opts Options
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWrapper creates and returns a new SQL driver with passed capabilities
|
|
||||||
func NewWrapper(d driver.Driver, opts ...Option) driver.Driver {
|
|
||||||
return &wrapperDriver{driver: d, opts: NewOptions(opts...), ctx: context.Background()}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrappedConnector struct {
|
|
||||||
connector driver.Connector
|
|
||||||
// name string
|
|
||||||
opts Options
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWrapperConnector(c driver.Connector, opts ...Option) driver.Connector {
|
|
||||||
return &wrappedConnector{connector: c, opts: NewOptions(opts...), ctx: context.Background()}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect implements driver.Driver Connect
|
|
||||||
func (w *wrappedConnector) Connect(ctx context.Context) (driver.Conn, error) {
|
|
||||||
return w.connector.Connect(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Driver implements driver.Driver Driver
|
|
||||||
func (w *wrappedConnector) Driver() driver.Driver {
|
|
||||||
return w.connector.Driver()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Connect implements driver.Driver OpenConnector
|
|
||||||
func (w *wrapperDriver) OpenConnector(name string) (driver.Conn, error) {
|
|
||||||
return &wrapperConnector{driver: w.driver, name: name, opts: w.opts}, nil
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Open implements driver.Driver Open
|
|
||||||
func (w *wrapperDriver) Open(name string) (driver.Conn, error) {
|
|
||||||
// ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) // Ensure eventual timeout
|
|
||||||
// defer cancel()
|
|
||||||
|
|
||||||
/*
|
|
||||||
connector, err := w.OpenConnector(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return connector.Connect(ctx)
|
|
||||||
*/
|
|
||||||
|
|
||||||
ts := time.Now()
|
|
||||||
c, err := w.driver.Open(name)
|
|
||||||
td := time.Since(ts)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled {
|
|
||||||
w.opts.Logger.Log(w.ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(w.ctx, "Open", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
_ = td
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return wrapConn(c, w.opts), nil
|
|
||||||
}
|
|
||||||
165
hooks/sql/gen.go
165
hooks/sql/gen.go
@@ -1,165 +0,0 @@
|
|||||||
//go:build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var connIfaces = []string{
|
|
||||||
"driver.ConnBeginTx",
|
|
||||||
"driver.ConnPrepareContext",
|
|
||||||
"driver.Execer",
|
|
||||||
"driver.ExecerContext",
|
|
||||||
"driver.NamedValueChecker",
|
|
||||||
"driver.Pinger",
|
|
||||||
"driver.Queryer",
|
|
||||||
"driver.QueryerContext",
|
|
||||||
"driver.SessionResetter",
|
|
||||||
"driver.Validator",
|
|
||||||
}
|
|
||||||
|
|
||||||
var stmtIfaces = []string{
|
|
||||||
"driver.StmtExecContext",
|
|
||||||
"driver.StmtQueryContext",
|
|
||||||
"driver.ColumnConverter",
|
|
||||||
"driver.NamedValueChecker",
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHash(s []string) string {
|
|
||||||
h := md5.New()
|
|
||||||
io.WriteString(h, strings.Join(s, "|"))
|
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
comboConn := all(connIfaces)
|
|
||||||
|
|
||||||
sort.Slice(comboConn, func(i, j int) bool {
|
|
||||||
return len(comboConn[i]) < len(comboConn[j])
|
|
||||||
})
|
|
||||||
|
|
||||||
comboStmt := all(stmtIfaces)
|
|
||||||
|
|
||||||
sort.Slice(comboStmt, func(i, j int) bool {
|
|
||||||
return len(comboStmt[i]) < len(comboStmt[j])
|
|
||||||
})
|
|
||||||
|
|
||||||
b := bytes.NewBuffer(nil)
|
|
||||||
b.WriteString("// Code generated. DO NOT EDIT.\n\n")
|
|
||||||
b.WriteString("package sql\n\n")
|
|
||||||
b.WriteString(`import "database/sql/driver"`)
|
|
||||||
b.WriteString("\n\n")
|
|
||||||
|
|
||||||
b.WriteString("func wrapConn(dc driver.Conn, opts Options) driver.Conn {\n")
|
|
||||||
b.WriteString("\tc := &wrapperConn{conn: dc, opts: opts}\n")
|
|
||||||
|
|
||||||
for idx := len(comboConn) - 1; idx >= 0; idx-- {
|
|
||||||
ifaces := comboConn[idx]
|
|
||||||
n := len(ifaces)
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
h := getHash(ifaces)
|
|
||||||
b.WriteString(fmt.Sprintf("\tif _, ok := dc.(wrapConn%04d_%s); ok {\n", n, h))
|
|
||||||
b.WriteString("\t\treturn struct {\n")
|
|
||||||
b.WriteString(strings.Join(append([]string{"\t\t\tdriver.Conn"}, ifaces...), "\n\t\t\t"))
|
|
||||||
b.WriteString("\n\t\t}{")
|
|
||||||
for idx := range ifaces {
|
|
||||||
if idx > 0 {
|
|
||||||
b.WriteString(", ")
|
|
||||||
b.WriteString("c")
|
|
||||||
} else if idx == 0 {
|
|
||||||
b.WriteString("c")
|
|
||||||
} else {
|
|
||||||
b.WriteString("c")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.WriteString(", c}\n")
|
|
||||||
b.WriteString("\t}\n\n")
|
|
||||||
}
|
|
||||||
b.WriteString("\treturn c\n")
|
|
||||||
b.WriteString("}\n\n")
|
|
||||||
|
|
||||||
for idx := len(comboConn) - 1; idx >= 0; idx-- {
|
|
||||||
ifaces := comboConn[idx]
|
|
||||||
n := len(ifaces)
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
h := getHash(ifaces)
|
|
||||||
b.WriteString(fmt.Sprintf("// %s\n", strings.Join(ifaces, "|")))
|
|
||||||
b.WriteString(fmt.Sprintf("type wrapConn%04d_%s interface {\n", n, h))
|
|
||||||
for _, iface := range ifaces {
|
|
||||||
b.WriteString(fmt.Sprintf("\t%s\n", iface))
|
|
||||||
}
|
|
||||||
b.WriteString("}\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
b.WriteString("func wrapStmt(stmt driver.Stmt, query string, opts Options) driver.Stmt {\n")
|
|
||||||
b.WriteString("\tc := &wrapperStmt{stmt: stmt, query: query, opts: opts}\n")
|
|
||||||
|
|
||||||
for idx := len(comboStmt) - 1; idx >= 0; idx-- {
|
|
||||||
ifaces := comboStmt[idx]
|
|
||||||
n := len(ifaces)
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
h := getHash(ifaces)
|
|
||||||
b.WriteString(fmt.Sprintf("\tif _, ok := stmt.(wrapStmt%04d_%s); ok {\n", n, h))
|
|
||||||
b.WriteString("\t\treturn struct {\n")
|
|
||||||
b.WriteString(strings.Join(append([]string{"\t\t\tdriver.Stmt"}, ifaces...), "\n\t\t\t"))
|
|
||||||
b.WriteString("\n\t\t}{")
|
|
||||||
for idx := range ifaces {
|
|
||||||
if idx > 0 {
|
|
||||||
b.WriteString(", ")
|
|
||||||
b.WriteString("c")
|
|
||||||
} else if idx == 0 {
|
|
||||||
b.WriteString("c")
|
|
||||||
} else {
|
|
||||||
b.WriteString("c")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.WriteString(", c}\n")
|
|
||||||
b.WriteString("\t}\n\n")
|
|
||||||
}
|
|
||||||
b.WriteString("\treturn c\n")
|
|
||||||
b.WriteString("}\n")
|
|
||||||
|
|
||||||
for idx := len(comboStmt) - 1; idx >= 0; idx-- {
|
|
||||||
ifaces := comboStmt[idx]
|
|
||||||
n := len(ifaces)
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
h := getHash(ifaces)
|
|
||||||
b.WriteString(fmt.Sprintf("\n// %s\n", strings.Join(ifaces, "|")))
|
|
||||||
b.WriteString(fmt.Sprintf("type wrapStmt%04d_%s interface {\n", n, h))
|
|
||||||
for _, iface := range ifaces {
|
|
||||||
b.WriteString(fmt.Sprintf("\t%s\n", iface))
|
|
||||||
}
|
|
||||||
b.WriteString("}\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s", b.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// all returns all combinations for a given string array.
|
|
||||||
func all[T any](set []T) (subsets [][]T) {
|
|
||||||
length := uint(len(set))
|
|
||||||
for subsetBits := 1; subsetBits < (1 << length); subsetBits++ {
|
|
||||||
var subset []T
|
|
||||||
for object := uint(0); object < length; object++ {
|
|
||||||
if (subsetBits>>object)&1 == 1 {
|
|
||||||
subset = append(subset, set[object])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subsets = append(subsets, subset)
|
|
||||||
}
|
|
||||||
return subsets
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
|
||||||
"go.unistack.org/micro/v3/meter"
|
|
||||||
"go.unistack.org/micro/v3/tracer"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// DefaultMeterStatsInterval holds default stats interval
|
|
||||||
DefaultMeterStatsInterval = 5 * time.Second
|
|
||||||
// DefaultLoggerObserver used to prepare labels for logger
|
|
||||||
DefaultLoggerObserver = func(ctx context.Context, method string, query string, td time.Duration, err error) []interface{} {
|
|
||||||
labels := []interface{}{"db.method", method, "took", fmt.Sprintf("%v", td)}
|
|
||||||
if err != nil {
|
|
||||||
labels = append(labels, "error", err.Error())
|
|
||||||
}
|
|
||||||
if query != labelUnknown {
|
|
||||||
labels = append(labels, "query", query)
|
|
||||||
}
|
|
||||||
return labels
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
MaxOpenConnections = "micro_sql_max_open_conn"
|
|
||||||
OpenConnections = "micro_sql_open_conn"
|
|
||||||
InuseConnections = "micro_sql_inuse_conn"
|
|
||||||
IdleConnections = "micro_sql_idle_conn"
|
|
||||||
WaitConnections = "micro_sql_waited_conn"
|
|
||||||
BlockedSeconds = "micro_sql_blocked_seconds"
|
|
||||||
MaxIdleClosed = "micro_sql_max_idle_closed"
|
|
||||||
MaxIdletimeClosed = "micro_sql_closed_max_idle"
|
|
||||||
MaxLifetimeClosed = "micro_sql_closed_max_lifetime"
|
|
||||||
|
|
||||||
meterRequestTotal = "micro_sql_request_total"
|
|
||||||
meterRequestLatencyMicroseconds = "micro_sql_latency_microseconds"
|
|
||||||
meterRequestDurationSeconds = "micro_sql_request_duration_seconds"
|
|
||||||
|
|
||||||
labelUnknown = "unknown"
|
|
||||||
labelQuery = "db_statement"
|
|
||||||
labelMethod = "db_method"
|
|
||||||
labelStatus = "status"
|
|
||||||
labelSuccess = "success"
|
|
||||||
labelFailure = "failure"
|
|
||||||
labelHost = "db_host"
|
|
||||||
labelDatabase = "db_name"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options struct holds wrapper options
|
|
||||||
type Options struct {
|
|
||||||
Logger logger.Logger
|
|
||||||
Meter meter.Meter
|
|
||||||
Tracer tracer.Tracer
|
|
||||||
DatabaseHost string
|
|
||||||
DatabaseName string
|
|
||||||
MeterStatsInterval time.Duration
|
|
||||||
LoggerLevel logger.Level
|
|
||||||
LoggerEnabled bool
|
|
||||||
LoggerObserver func(ctx context.Context, method string, name string, td time.Duration, err error) []interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option func signature
|
|
||||||
type Option func(*Options)
|
|
||||||
|
|
||||||
// NewOptions create new Options struct from provided option slice
|
|
||||||
func NewOptions(opts ...Option) Options {
|
|
||||||
options := Options{
|
|
||||||
Logger: logger.DefaultLogger,
|
|
||||||
Meter: meter.DefaultMeter,
|
|
||||||
Tracer: tracer.DefaultTracer,
|
|
||||||
MeterStatsInterval: DefaultMeterStatsInterval,
|
|
||||||
LoggerLevel: logger.ErrorLevel,
|
|
||||||
LoggerObserver: DefaultLoggerObserver,
|
|
||||||
}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
options.Meter = options.Meter.Clone(
|
|
||||||
meter.Labels(
|
|
||||||
labelHost, options.DatabaseHost,
|
|
||||||
labelDatabase, options.DatabaseName,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
options.Logger = options.Logger.Clone(logger.WithAddCallerSkipCount(1))
|
|
||||||
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
// MetricInterval specifies stats interval for *sql.DB
|
|
||||||
func MetricInterval(td time.Duration) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.MeterStatsInterval = td
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DatabaseHost(host string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.DatabaseHost = host
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DatabaseName(name string) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.DatabaseName = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Meter passes meter.Meter to wrapper
|
|
||||||
func Meter(m meter.Meter) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Meter = m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger passes logger.Logger to wrapper
|
|
||||||
func Logger(l logger.Logger) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Logger = l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerEnabled enable sql logging
|
|
||||||
func LoggerEnabled(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.LoggerEnabled = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerLevel passes logger.Level option
|
|
||||||
func LoggerLevel(lvl logger.Level) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.LoggerLevel = lvl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerObserver passes observer to fill logger fields
|
|
||||||
func LoggerObserver(obs func(context.Context, string, string, time.Duration, error) []interface{}) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.LoggerObserver = obs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracer passes tracer.Tracer to wrapper
|
|
||||||
func Tracer(t tracer.Tracer) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.Tracer = t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type queryNameKey struct{}
|
|
||||||
|
|
||||||
// QueryName passes query name to wrapper func
|
|
||||||
func QueryName(ctx context.Context, name string) context.Context {
|
|
||||||
if ctx == nil {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
return context.WithValue(ctx, queryNameKey{}, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getQueryName(ctx context.Context) string {
|
|
||||||
if v, ok := ctx.Value(queryNameKey{}).(string); ok && v != labelUnknown {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return getCallerName()
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Statser interface {
|
|
||||||
Stats() sql.DBStats
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStatsMeter(ctx context.Context, db Statser, opts ...Option) {
|
|
||||||
options := NewOptions(opts...)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
ticker := time.NewTicker(options.MeterStatsInterval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
if db == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
stats := db.Stats()
|
|
||||||
options.Meter.Counter(MaxOpenConnections).Set(uint64(stats.MaxOpenConnections))
|
|
||||||
options.Meter.Counter(OpenConnections).Set(uint64(stats.OpenConnections))
|
|
||||||
options.Meter.Counter(InuseConnections).Set(uint64(stats.InUse))
|
|
||||||
options.Meter.Counter(IdleConnections).Set(uint64(stats.Idle))
|
|
||||||
options.Meter.Counter(WaitConnections).Set(uint64(stats.WaitCount))
|
|
||||||
options.Meter.FloatCounter(BlockedSeconds).Set(stats.WaitDuration.Seconds())
|
|
||||||
options.Meter.Counter(MaxIdleClosed).Set(uint64(stats.MaxIdleClosed))
|
|
||||||
options.Meter.Counter(MaxIdletimeClosed).Set(uint64(stats.MaxIdleTimeClosed))
|
|
||||||
options.Meter.Counter(MaxLifetimeClosed).Set(uint64(stats.MaxLifetimeClosed))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql/driver"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/hooks/requestid"
|
|
||||||
"go.unistack.org/micro/v3/tracer"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ driver.Stmt = (*wrapperStmt)(nil)
|
|
||||||
_ driver.StmtQueryContext = (*wrapperStmt)(nil)
|
|
||||||
_ driver.StmtExecContext = (*wrapperStmt)(nil)
|
|
||||||
_ driver.NamedValueChecker = (*wrapperStmt)(nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// wrapperStmt defines a wrapper for driver.Stmt
|
|
||||||
type wrapperStmt struct {
|
|
||||||
stmt driver.Stmt
|
|
||||||
opts Options
|
|
||||||
query string
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements driver.Stmt Close
|
|
||||||
func (w *wrapperStmt) Close() error {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Close"}
|
|
||||||
ts := time.Now()
|
|
||||||
err := w.stmt.Close()
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Close", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumInput implements driver.Stmt NumInput
|
|
||||||
func (w *wrapperStmt) NumInput() int {
|
|
||||||
return w.stmt.NumInput()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckNamedValue implements driver.NamedValueChecker
|
|
||||||
func (w *wrapperStmt) CheckNamedValue(v *driver.NamedValue) error {
|
|
||||||
s, ok := w.stmt.(driver.NamedValueChecker)
|
|
||||||
if !ok {
|
|
||||||
return driver.ErrSkip
|
|
||||||
}
|
|
||||||
return s.CheckNamedValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec implements driver.Stmt Exec
|
|
||||||
func (w *wrapperStmt) Exec(args []driver.Value) (driver.Result, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Exec"}
|
|
||||||
ts := time.Now()
|
|
||||||
res, err := w.stmt.Exec(args) // nolint:staticcheck
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Exec", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Query implements driver.Stmt Query
|
|
||||||
func (w *wrapperStmt) Query(args []driver.Value) (driver.Rows, error) {
|
|
||||||
var ctx context.Context
|
|
||||||
if w.ctx != nil {
|
|
||||||
ctx = w.ctx
|
|
||||||
} else {
|
|
||||||
ctx = context.Background()
|
|
||||||
}
|
|
||||||
_ = ctx
|
|
||||||
labels := []string{labelMethod, "Query"}
|
|
||||||
ts := time.Now()
|
|
||||||
rows, err := w.stmt.Query(args) // nolint:staticcheck
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "Query", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return rows, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColumnConverter implements driver.ColumnConverter
|
|
||||||
func (w *wrapperStmt) ColumnConverter(idx int) driver.ValueConverter {
|
|
||||||
s, ok := w.stmt.(driver.ColumnConverter) // nolint:staticcheck
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return s.ColumnConverter(idx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecContext implements driver.StmtExecContext ExecContext
|
|
||||||
func (w *wrapperStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
|
|
||||||
var nctx context.Context
|
|
||||||
var span tracer.Span
|
|
||||||
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "ExecContext")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
defer span.Finish()
|
|
||||||
if len(args) > 0 {
|
|
||||||
span.AddLabels("db.args", fmt.Sprintf("%v", namedValueToLabels(args)))
|
|
||||||
}
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "ExecContext", labelQuery, name}
|
|
||||||
|
|
||||||
if conn, ok := w.stmt.(driver.StmtExecContext); ok {
|
|
||||||
ts := time.Now()
|
|
||||||
res, err := conn.ExecContext(nctx, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "ExecContext", name, td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
values, err := namedValueToValue(args)
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "ExecContext", name, 0, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ts := time.Now()
|
|
||||||
res, err := w.Exec(values) // nolint:staticcheck
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "ExecContext", name, td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryContext implements driver.StmtQueryContext StmtQueryContext
|
|
||||||
func (w *wrapperStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
|
|
||||||
var nctx context.Context
|
|
||||||
var span tracer.Span
|
|
||||||
|
|
||||||
name := getQueryName(ctx)
|
|
||||||
if w.ctx != nil {
|
|
||||||
nctx, span = w.opts.Tracer.Start(w.ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
} else {
|
|
||||||
nctx, span = w.opts.Tracer.Start(ctx, "sdk.database", tracer.WithSpanKind(tracer.SpanKindClient))
|
|
||||||
}
|
|
||||||
span.AddLabels("db.method", "QueryContext")
|
|
||||||
span.AddLabels("db.statement", name)
|
|
||||||
defer span.Finish()
|
|
||||||
if len(args) > 0 {
|
|
||||||
span.AddLabels("db.args", fmt.Sprintf("%v", namedValueToLabels(args)))
|
|
||||||
}
|
|
||||||
if id, ok := ctx.Value(requestid.XRequestIDKey{}).(string); ok {
|
|
||||||
span.AddLabels("x-request-id", id)
|
|
||||||
}
|
|
||||||
labels := []string{labelMethod, "QueryContext", labelQuery, name}
|
|
||||||
if conn, ok := w.stmt.(driver.StmtQueryContext); ok {
|
|
||||||
ts := time.Now()
|
|
||||||
rows, err := conn.QueryContext(nctx, args)
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "QueryContext", name, td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return rows, err
|
|
||||||
}
|
|
||||||
|
|
||||||
values, err := namedValueToValue(args)
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "QueryContext", name, 0, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ts := time.Now()
|
|
||||||
rows, err := w.Query(values) // nolint:staticcheck
|
|
||||||
td := time.Since(ts)
|
|
||||||
te := td.Seconds()
|
|
||||||
if err != nil {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelFailure)...).Inc()
|
|
||||||
span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
} else {
|
|
||||||
w.opts.Meter.Counter(meterRequestTotal, append(labels, labelStatus, labelSuccess)...).Inc()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.opts.Meter.Summary(meterRequestLatencyMicroseconds, labels...).Update(te)
|
|
||||||
w.opts.Meter.Histogram(meterRequestDurationSeconds, labels...).Update(te)
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(ctx, "QueryContext", name, td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return rows, err
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql/driver"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/tracer"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ driver.Tx = (*wrapperTx)(nil)
|
|
||||||
|
|
||||||
// wrapperTx defines a wrapper for driver.Tx
|
|
||||||
type wrapperTx struct {
|
|
||||||
tx driver.Tx
|
|
||||||
span tracer.Span
|
|
||||||
opts Options
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit implements driver.Tx Commit
|
|
||||||
func (w *wrapperTx) Commit() error {
|
|
||||||
ts := time.Now()
|
|
||||||
err := w.tx.Commit()
|
|
||||||
td := time.Since(ts)
|
|
||||||
_ = td
|
|
||||||
if w.span != nil {
|
|
||||||
if err != nil {
|
|
||||||
w.span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
}
|
|
||||||
w.span.Finish()
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(w.ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(w.ctx, "Commit", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
w.ctx = nil
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rollback implements driver.Tx Rollback
|
|
||||||
func (w *wrapperTx) Rollback() error {
|
|
||||||
ts := time.Now()
|
|
||||||
err := w.tx.Rollback()
|
|
||||||
td := time.Since(ts)
|
|
||||||
_ = td
|
|
||||||
if w.span != nil {
|
|
||||||
if err != nil {
|
|
||||||
w.span.SetStatus(tracer.SpanStatusError, err.Error())
|
|
||||||
}
|
|
||||||
w.span.Finish()
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if w.opts.LoggerEnabled && w.opts.Logger.V(w.opts.LoggerLevel) {
|
|
||||||
w.opts.Logger.Log(w.ctx, w.opts.LoggerLevel, w.opts.LoggerObserver(w.ctx, "Rollback", getCallerName(), td, err)...)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
w.ctx = nil
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package sql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql/driver"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
func wrapDriver(d driver.Driver, opts Options) driver.Driver {
|
|
||||||
if _, ok := d.(driver.DriverContext); ok {
|
|
||||||
return &wrapperDriver{driver: d, opts: opts}
|
|
||||||
}
|
|
||||||
return struct{ driver.Driver }{&wrapperDriver{driver: d, opts: opts}}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// WrapConn allows an existing driver.Conn to be wrapped.
|
|
||||||
func WrapConn(c driver.Conn, opts ...Option) driver.Conn {
|
|
||||||
return wrapConn(c, NewOptions(opts...))
|
|
||||||
}
|
|
||||||
20699
hooks/sql/wrap_gen.go
20699
hooks/sql/wrap_gen.go
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
|||||||
package validator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/client"
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
|
||||||
"go.unistack.org/micro/v3/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultClientErrorFunc = func(req client.Request, rsp interface{}, err error) error {
|
|
||||||
if rsp != nil {
|
|
||||||
return errors.BadGateway(req.Service(), "%v", err)
|
|
||||||
}
|
|
||||||
return errors.BadRequest(req.Service(), "%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultServerErrorFunc = func(req server.Request, rsp interface{}, err error) error {
|
|
||||||
if rsp != nil {
|
|
||||||
return errors.BadGateway(req.Service(), "%v", err)
|
|
||||||
}
|
|
||||||
return errors.BadRequest(req.Service(), "%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultPublishErrorFunc = func(msg client.Message, err error) error {
|
|
||||||
return errors.BadRequest(msg.Topic(), "%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultSubscribeErrorFunc = func(msg server.Message, err error) error {
|
|
||||||
return errors.BadRequest(msg.Topic(), "%v", err)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
ClientErrorFunc func(client.Request, interface{}, error) error
|
|
||||||
ServerErrorFunc func(server.Request, interface{}, error) error
|
|
||||||
PublishErrorFunc func(client.Message, error) error
|
|
||||||
SubscribeErrorFunc func(server.Message, error) error
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options struct holds wrapper options
|
|
||||||
type Options struct {
|
|
||||||
ClientErrorFn ClientErrorFunc
|
|
||||||
ServerErrorFn ServerErrorFunc
|
|
||||||
PublishErrorFn PublishErrorFunc
|
|
||||||
SubscribeErrorFn SubscribeErrorFunc
|
|
||||||
ClientValidateResponse bool
|
|
||||||
ServerValidateResponse bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Option func signature
|
|
||||||
type Option func(*Options)
|
|
||||||
|
|
||||||
func ClientValidateResponse(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ClientValidateResponse = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServerValidateResponse(b bool) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ClientValidateResponse = b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClientReqErrorFn(fn ClientErrorFunc) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ClientErrorFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ServerErrorFn(fn ServerErrorFunc) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.ServerErrorFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PublishErrorFn(fn PublishErrorFunc) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.PublishErrorFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SubscribeErrorFn(fn SubscribeErrorFunc) Option {
|
|
||||||
return func(o *Options) {
|
|
||||||
o.SubscribeErrorFn = fn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewOptions(opts ...Option) Options {
|
|
||||||
options := Options{
|
|
||||||
ClientErrorFn: DefaultClientErrorFunc,
|
|
||||||
ServerErrorFn: DefaultServerErrorFunc,
|
|
||||||
PublishErrorFn: DefaultPublishErrorFunc,
|
|
||||||
SubscribeErrorFn: DefaultSubscribeErrorFunc,
|
|
||||||
}
|
|
||||||
for _, o := range opts {
|
|
||||||
o(&options)
|
|
||||||
}
|
|
||||||
return options
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHook(opts ...Option) *hook {
|
|
||||||
return &hook{opts: NewOptions(opts...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type validator interface {
|
|
||||||
Validate() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type hook struct {
|
|
||||||
opts Options
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientCall(next client.FuncCall) client.FuncCall {
|
|
||||||
return func(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
|
||||||
if v, ok := req.Body().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return w.opts.ClientErrorFn(req, nil, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := next(ctx, req, rsp, opts...)
|
|
||||||
if v, ok := rsp.(validator); ok && w.opts.ClientValidateResponse {
|
|
||||||
if verr := v.Validate(); verr != nil {
|
|
||||||
return w.opts.ClientErrorFn(req, rsp, verr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientStream(next client.FuncStream) client.FuncStream {
|
|
||||||
return func(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
|
||||||
if v, ok := req.Body().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return nil, w.opts.ClientErrorFn(req, nil, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next(ctx, req, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientPublish(next client.FuncPublish) client.FuncPublish {
|
|
||||||
return func(ctx context.Context, msg client.Message, opts ...client.PublishOption) error {
|
|
||||||
if v, ok := msg.Payload().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return w.opts.PublishErrorFn(msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next(ctx, msg, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ClientBatchPublish(next client.FuncBatchPublish) client.FuncBatchPublish {
|
|
||||||
return func(ctx context.Context, msgs []client.Message, opts ...client.PublishOption) error {
|
|
||||||
for _, msg := range msgs {
|
|
||||||
if v, ok := msg.Payload().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return w.opts.PublishErrorFn(msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next(ctx, msgs, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerHandler(next server.FuncHandler) server.FuncHandler {
|
|
||||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
|
||||||
if v, ok := req.Body().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return w.opts.ServerErrorFn(req, nil, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := next(ctx, req, rsp)
|
|
||||||
if v, ok := rsp.(validator); ok && w.opts.ServerValidateResponse {
|
|
||||||
if verr := v.Validate(); verr != nil {
|
|
||||||
return w.opts.ServerErrorFn(req, rsp, verr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *hook) ServerSubscriber(next server.FuncSubHandler) server.FuncSubHandler {
|
|
||||||
return func(ctx context.Context, msg server.Message) error {
|
|
||||||
if v, ok := msg.Body().(validator); ok {
|
|
||||||
if err := v.Validate(); err != nil {
|
|
||||||
return w.opts.SubscribeErrorFn(msg, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next(ctx, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func signature
|
// Option func signature
|
||||||
@@ -99,7 +99,6 @@ func WithAddFields(fields ...interface{}) Option {
|
|||||||
iv, iok := o.Fields[i].(string)
|
iv, iok := o.Fields[i].(string)
|
||||||
jv, jok := fields[j].(string)
|
jv, jok := fields[j].(string)
|
||||||
if iok && jok && iv == jv {
|
if iok && jok && iv == jv {
|
||||||
o.Fields[i+1] = fields[j+1]
|
|
||||||
fields = slices.Delete(fields, j, j+2)
|
fields = slices.Delete(fields, j, j+2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/semconv"
|
"go.unistack.org/micro/v4/semconv"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -278,7 +278,7 @@ func (s *slogLogger) printLog(ctx context.Context, lvl logger.Level, msg string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.opts.AddStacktrace && (lvl == logger.FatalLevel || lvl == logger.ErrorLevel) {
|
if (s.opts.AddStacktrace || lvl == logger.FatalLevel) || (s.opts.AddStacktrace && lvl == logger.ErrorLevel) {
|
||||||
stackInfo := make([]byte, 1024*1024)
|
stackInfo := make([]byte, 1024*1024)
|
||||||
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
if stackSize := runtime.Stack(stackInfo, false); stackSize > 0 {
|
||||||
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
|
traceLines := reTrace.Split(string(stackInfo[:stackSize]), -1)
|
||||||
|
|||||||
@@ -12,16 +12,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/util/buffer"
|
"go.unistack.org/micro/v4/util/buffer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// always first to have proper check
|
// always first to have proper check
|
||||||
func TestStacktrace(t *testing.T) {
|
func TestStacktrace(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
l := NewLogger(logger.WithLevel(logger.DebugLevel), logger.WithOutput(buf),
|
l := NewLogger(logger.WithLevel(logger.ErrorLevel), logger.WithOutput(buf),
|
||||||
WithHandlerFunc(slog.NewTextHandler),
|
WithHandlerFunc(slog.NewTextHandler),
|
||||||
logger.WithAddStacktrace(true),
|
logger.WithAddStacktrace(true),
|
||||||
)
|
)
|
||||||
@@ -124,7 +124,7 @@ func TestWithDedupKeysWithAddFields(t *testing.T) {
|
|||||||
|
|
||||||
l.Info(ctx, "msg3")
|
l.Info(ctx, "msg3")
|
||||||
|
|
||||||
if !bytes.Contains(buf.Bytes(), []byte(`msg=msg3 key1=val4 key2=val3`)) {
|
if !bytes.Contains(buf.Bytes(), []byte(`msg=msg3 key1=val1 key2=val2`)) {
|
||||||
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
t.Fatalf("logger error not works, buf contains: %s", buf.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const sf = "0-+# "
|
const sf = "0-+# "
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUnwrap(t *testing.T) {
|
func TestUnwrap(t *testing.T) {
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !exclude
|
||||||
|
|
||||||
// Package metadata is a way of defining message headers
|
// Package metadata is a way of defining message headers
|
||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !exclude
|
||||||
|
|
||||||
// Package metadata is a way of defining message headers
|
// Package metadata is a way of defining message headers
|
||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
|
|||||||
282
metadata/metadata_grpc.go
Normal file
282
metadata/metadata_grpc.go
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
//go:build exclude
|
||||||
|
|
||||||
|
// Package metadata TODO need compare with micro metadata
|
||||||
|
package metadata // import "google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MD is a mapping from metadata keys to values. Users should use the following
|
||||||
|
// two convenience functions New and Pairs to generate MD.
|
||||||
|
type MD map[string][]string
|
||||||
|
|
||||||
|
type Metadata map[string]string
|
||||||
|
|
||||||
|
// New creates an MD from a given key-value map.
|
||||||
|
//
|
||||||
|
// Only the following ASCII characters are allowed in keys:
|
||||||
|
// - digits: 0-9
|
||||||
|
// - uppercase letters: A-Z (normalized to lower)
|
||||||
|
// - lowercase letters: a-z
|
||||||
|
// - special characters: -_.
|
||||||
|
//
|
||||||
|
// Uppercase letters are automatically converted to lowercase.
|
||||||
|
//
|
||||||
|
// Keys beginning with "grpc-" are reserved for grpc-internal use only and may
|
||||||
|
// result in errors if set in metadata.
|
||||||
|
func New(m map[string]string) MD {
|
||||||
|
md := make(MD, len(m))
|
||||||
|
for k, val := range m {
|
||||||
|
key := strings.ToLower(k)
|
||||||
|
md[key] = append(md[key], val)
|
||||||
|
}
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pairs returns an MD formed by the mapping of key, value ...
|
||||||
|
// Pairs panics if len(kv) is odd.
|
||||||
|
//
|
||||||
|
// Only the following ASCII characters are allowed in keys:
|
||||||
|
// - digits: 0-9
|
||||||
|
// - uppercase letters: A-Z (normalized to lower)
|
||||||
|
// - lowercase letters: a-z
|
||||||
|
// - special characters: -_.
|
||||||
|
//
|
||||||
|
// Uppercase letters are automatically converted to lowercase.
|
||||||
|
//
|
||||||
|
// Keys beginning with "grpc-" are reserved for grpc-internal use only and may
|
||||||
|
// result in errors if set in metadata.
|
||||||
|
func Pairs(kv ...string) MD {
|
||||||
|
if len(kv)%2 == 1 {
|
||||||
|
panic(fmt.Sprintf("metadata: Pairs got the odd number of input pairs for metadata: %d", len(kv)))
|
||||||
|
}
|
||||||
|
md := make(MD, len(kv)/2)
|
||||||
|
for i := 0; i < len(kv); i += 2 {
|
||||||
|
key := strings.ToLower(kv[i])
|
||||||
|
md[key] = append(md[key], kv[i+1])
|
||||||
|
}
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of items in md.
|
||||||
|
func (md MD) Len() int {
|
||||||
|
return len(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of md.
|
||||||
|
func (md MD) Copy() MD {
|
||||||
|
out := make(MD, len(md))
|
||||||
|
for k, v := range md {
|
||||||
|
out[k] = copyOf(v)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get obtains the values for a given key.
|
||||||
|
//
|
||||||
|
// k is converted to lowercase before searching in md.
|
||||||
|
func (md MD) Get(k string) []string {
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
return md[k]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of a given key with a slice of values.
|
||||||
|
//
|
||||||
|
// k is converted to lowercase before storing in md.
|
||||||
|
func (md MD) Set(k string, vals ...string) {
|
||||||
|
if len(vals) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
md[k] = vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append adds the values to key k, not overwriting what was already stored at
|
||||||
|
// that key.
|
||||||
|
//
|
||||||
|
// k is converted to lowercase before storing in md.
|
||||||
|
func (md MD) Append(k string, vals ...string) {
|
||||||
|
if len(vals) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
md[k] = append(md[k], vals...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete removes the values for a given key k which is converted to lowercase
|
||||||
|
// before removing it from md.
|
||||||
|
func (md MD) Delete(k string) {
|
||||||
|
k = strings.ToLower(k)
|
||||||
|
delete(md, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join joins any number of mds into a single MD.
|
||||||
|
//
|
||||||
|
// The order of values for each key is determined by the order in which the mds
|
||||||
|
// containing those values are presented to Join.
|
||||||
|
func Join(mds ...MD) MD {
|
||||||
|
out := MD{}
|
||||||
|
for _, md := range mds {
|
||||||
|
for k, v := range md {
|
||||||
|
out[k] = append(out[k], v...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
type mdIncomingKey struct{}
|
||||||
|
type mdOutgoingKey struct{}
|
||||||
|
|
||||||
|
// NewIncomingContext creates a new context with incoming md attached. md must
|
||||||
|
// not be modified after calling this function.
|
||||||
|
func NewIncomingContext(ctx context.Context, md Metadata) context.Context {
|
||||||
|
in := make(MD, len(md))
|
||||||
|
for k, v := range md {
|
||||||
|
in[k] = []string{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.WithValue(ctx, mdIncomingKey{}, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutgoingContext creates a new context with outgoing md attached. If used
|
||||||
|
// in conjunction with AppendToOutgoingContext, NewOutgoingContext will
|
||||||
|
// overwrite any previously-appended metadata. md must not be modified after
|
||||||
|
// calling this function.
|
||||||
|
func NewOutgoingContext(ctx context.Context, md Metadata) context.Context {
|
||||||
|
out := make(MD, len(md))
|
||||||
|
for k, v := range md {
|
||||||
|
out[k] = []string{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: out})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendToOutgoingContext returns a new context with the provided kv merged
|
||||||
|
// with any existing metadata in the context. Please refer to the documentation
|
||||||
|
// of Pairs for a description of kv.
|
||||||
|
func AppendToOutgoingContext(ctx context.Context, kv ...string) context.Context {
|
||||||
|
if len(kv)%2 == 1 {
|
||||||
|
panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv)))
|
||||||
|
}
|
||||||
|
md, _ := ctx.Value(mdOutgoingKey{}).(rawMD)
|
||||||
|
added := make([][]string, len(md.added)+1)
|
||||||
|
copy(added, md.added)
|
||||||
|
kvCopy := make([]string, 0, len(kv))
|
||||||
|
for i := 0; i < len(kv); i += 2 {
|
||||||
|
kvCopy = append(kvCopy, strings.ToLower(kv[i]), kv[i+1])
|
||||||
|
}
|
||||||
|
added[len(added)-1] = kvCopy
|
||||||
|
return context.WithValue(ctx, mdOutgoingKey{}, rawMD{md: md.md, added: added})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromIncomingContext returns the incoming metadata in ctx if it exists.
|
||||||
|
//
|
||||||
|
// All keys in the returned MD are lowercase.
|
||||||
|
func FromIncomingContext(ctx context.Context) (Metadata, bool) {
|
||||||
|
md, ok := ctx.Value(mdIncomingKey{}).(MD)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
out := make(Metadata, len(md))
|
||||||
|
for k, v := range md {
|
||||||
|
// We need to manually convert all keys to lower case, because MD is a
|
||||||
|
// map, and there's no guarantee that the MD attached to the context is
|
||||||
|
// created using our helper functions.
|
||||||
|
|
||||||
|
if len(v) > 0 {
|
||||||
|
key := strings.ToLower(k)
|
||||||
|
out[key] = v[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return out, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValueFromIncomingContext returns the metadata value corresponding to the metadata
|
||||||
|
// key from the incoming metadata if it exists. Keys are matched in a case insensitive
|
||||||
|
// manner.
|
||||||
|
func ValueFromIncomingContext(ctx context.Context, key string) []string {
|
||||||
|
md, ok := ctx.Value(mdIncomingKey{}).(MD)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := md[key]; ok {
|
||||||
|
return copyOf(v)
|
||||||
|
}
|
||||||
|
for k, v := range md {
|
||||||
|
// Case insensitive comparison: MD is a map, and there's no guarantee
|
||||||
|
// that the MD attached to the context is created using our helper
|
||||||
|
// functions.
|
||||||
|
if strings.EqualFold(k, key) {
|
||||||
|
return copyOf(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyOf(v []string) []string {
|
||||||
|
vals := make([]string, len(v))
|
||||||
|
copy(vals, v)
|
||||||
|
return vals
|
||||||
|
}
|
||||||
|
|
||||||
|
// fromOutgoingContextRaw returns the un-merged, intermediary contents of rawMD.
|
||||||
|
//
|
||||||
|
// Remember to perform strings.ToLower on the keys, for both the returned MD (MD
|
||||||
|
// is a map, there's no guarantee it's created using our helper functions) and
|
||||||
|
// the extra kv pairs (AppendToOutgoingContext doesn't turn them into
|
||||||
|
// lowercase).
|
||||||
|
func fromOutgoingContextRaw(ctx context.Context) (MD, [][]string, bool) {
|
||||||
|
raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return raw.md, raw.added, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromOutgoingContext returns the outgoing metadata in ctx if it exists.
|
||||||
|
//
|
||||||
|
// All keys in the returned MD are lowercase.
|
||||||
|
func FromOutgoingContext(ctx context.Context) (Metadata, bool) {
|
||||||
|
raw, ok := ctx.Value(mdOutgoingKey{}).(rawMD)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
mdSize := len(raw.md)
|
||||||
|
for i := range raw.added {
|
||||||
|
mdSize += len(raw.added[i]) / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make(Metadata, mdSize)
|
||||||
|
for k, v := range raw.md {
|
||||||
|
// We need to manually convert all keys to lower case, because MD is a
|
||||||
|
// map, and there's no guarantee that the MD attached to the context is
|
||||||
|
// created using our helper functions.
|
||||||
|
if len(v) > 0 {
|
||||||
|
key := strings.ToLower(k)
|
||||||
|
out[key] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, added := range raw.added {
|
||||||
|
if len(added)%2 == 1 {
|
||||||
|
panic(fmt.Sprintf("metadata: FromOutgoingContext got an odd number of input pairs for metadata: %d", len(added)))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(added); i += 2 {
|
||||||
|
key := strings.ToLower(added[i])
|
||||||
|
out[key] = added[i+1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
type rawMD struct {
|
||||||
|
md MD
|
||||||
|
added [][]string
|
||||||
|
}
|
||||||
30
micro.go
30
micro.go
@@ -3,21 +3,21 @@ package micro
|
|||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/flow"
|
"go.unistack.org/micro/v4/flow"
|
||||||
"go.unistack.org/micro/v3/fsm"
|
"go.unistack.org/micro/v4/fsm"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
"go.unistack.org/micro/v3/store"
|
"go.unistack.org/micro/v4/store"
|
||||||
"go.unistack.org/micro/v3/sync"
|
"go.unistack.org/micro/v4/sync"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func As(b any, target any) bool {
|
func As(b any, target any) bool {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/fsm"
|
"go.unistack.org/micro/v4/fsm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAs(t *testing.T) {
|
func TestAs(t *testing.T) {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error is network node errors
|
// Error is network node errors
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/network/tunnel"
|
"go.unistack.org/micro/v4/network/tunnel"
|
||||||
"go.unistack.org/micro/v3/proxy"
|
"go.unistack.org/micro/v4/proxy"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
maddr "go.unistack.org/micro/v3/util/addr"
|
maddr "go.unistack.org/micro/v4/util/addr"
|
||||||
mnet "go.unistack.org/micro/v3/util/net"
|
mnet "go.unistack.org/micro/v4/util/net"
|
||||||
"go.unistack.org/micro/v3/util/rand"
|
"go.unistack.org/micro/v4/util/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memorySocket struct {
|
type memorySocket struct {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options struct holds the transport options
|
// Options struct holds the transport options
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/network/transport"
|
"go.unistack.org/micro/v4/network/transport"
|
||||||
"go.unistack.org/micro/v3/network/tunnel"
|
"go.unistack.org/micro/v4/network/tunnel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunBroker struct {
|
type tunBroker struct {
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package tunnel
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/network/transport"
|
"go.unistack.org/micro/v4/network/transport"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package transport
|
package transport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/network/transport"
|
"go.unistack.org/micro/v4/network/transport"
|
||||||
"go.unistack.org/micro/v3/network/tunnel"
|
"go.unistack.org/micro/v4/network/tunnel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunListener struct {
|
type tunListener struct {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/network/transport"
|
"go.unistack.org/micro/v4/network/transport"
|
||||||
"go.unistack.org/micro/v3/network/tunnel"
|
"go.unistack.org/micro/v4/network/tunnel"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tunTransport struct {
|
type tunTransport struct {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/network/transport"
|
"go.unistack.org/micro/v4/network/transport"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultTunnel contains default tunnel implementation
|
// DefaultTunnel contains default tunnel implementation
|
||||||
|
|||||||
22
options.go
22
options.go
@@ -5,17 +5,17 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/config"
|
"go.unistack.org/micro/v4/config"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
"go.unistack.org/micro/v3/store"
|
"go.unistack.org/micro/v4/store"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options for micro service
|
// Options for micro service
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
profile "go.unistack.org/micro/v3/profiler"
|
profile "go.unistack.org/micro/v4/profiler"
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpProfile struct {
|
type httpProfile struct {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
profile "go.unistack.org/micro/v3/profiler"
|
profile "go.unistack.org/micro/v4/profiler"
|
||||||
)
|
)
|
||||||
|
|
||||||
type profiler struct {
|
type profiler struct {
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options for proxy
|
// Options for proxy
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package proxy
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultEndpoint holds default proxy address
|
// DefaultEndpoint holds default proxy address
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testData = map[string][]*register.Service{
|
var testData = map[string][]*register.Service{
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options holds options for register
|
// Options holds options for register
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver is a DNS network resolve
|
// Resolver is a DNS network resolve
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver is a DNS network resolve
|
// Resolver is a DNS network resolve
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// nolint: golint,revive
|
// nolint: golint,revive
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package noop
|
package noop
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver contains noop resolver
|
// Resolver contains noop resolver
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ package register
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver is a register network resolver
|
// Resolver is a register network resolver
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
package static
|
package static
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/resolver"
|
"go.unistack.org/micro/v4/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver returns a static list of nodes. In the event the node list
|
// Resolver returns a static list of nodes. In the event the node list
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package router
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options are router options
|
// Options are router options
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package router
|
|||||||
import (
|
import (
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package random
|
package random
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
"go.unistack.org/micro/v3/util/rand"
|
"go.unistack.org/micro/v4/util/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type random struct{}
|
type random struct{}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package random
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRandom(t *testing.T) {
|
func TestRandom(t *testing.T) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package roundrobin
|
package roundrobin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
"go.unistack.org/micro/v3/util/rand"
|
"go.unistack.org/micro/v4/util/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSelector returns an initialised round robin selector
|
// NewSelector returns an initialised round robin selector
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package roundrobin
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/selector"
|
"go.unistack.org/micro/v4/selector"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRoundRobin(t *testing.T) {
|
func TestRoundRobin(t *testing.T) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import "go.unistack.org/micro/v3/errors"
|
import "go.unistack.org/micro/v4/errors"
|
||||||
|
|
||||||
type Error struct {
|
type Error struct {
|
||||||
id string
|
id string
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package server
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
func TestError(t *testing.T) {
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
maddr "go.unistack.org/micro/v3/util/addr"
|
maddr "go.unistack.org/micro/v4/util/addr"
|
||||||
mnet "go.unistack.org/micro/v3/util/net"
|
mnet "go.unistack.org/micro/v4/util/net"
|
||||||
"go.unistack.org/micro/v3/util/rand"
|
"go.unistack.org/micro/v4/util/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultCodecs will be used to encode/decode
|
// DefaultCodecs will be used to encode/decode
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TestHandler struct {
|
type TestHandler struct {
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/options"
|
"go.unistack.org/micro/v4/options"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
msync "go.unistack.org/micro/v3/sync"
|
msync "go.unistack.org/micro/v4/sync"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
"go.unistack.org/micro/v3/util/id"
|
"go.unistack.org/micro/v4/util/id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option func
|
// Option func
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/util/addr"
|
"go.unistack.org/micro/v4/util/addr"
|
||||||
"go.unistack.org/micro/v3/util/backoff"
|
"go.unistack.org/micro/v4/util/backoff"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultServer default server
|
// DefaultServer default server
|
||||||
|
|||||||
42
service.go
42
service.go
@@ -9,17 +9,17 @@ import (
|
|||||||
|
|
||||||
"github.com/KimMachineGun/automemlimit/memlimit"
|
"github.com/KimMachineGun/automemlimit/memlimit"
|
||||||
"go.uber.org/automaxprocs/maxprocs"
|
"go.uber.org/automaxprocs/maxprocs"
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/client"
|
"go.unistack.org/micro/v4/client"
|
||||||
"go.unistack.org/micro/v3/config"
|
"go.unistack.org/micro/v4/config"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/router"
|
"go.unistack.org/micro/v4/router"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
"go.unistack.org/micro/v3/store"
|
"go.unistack.org/micro/v4/store"
|
||||||
"go.unistack.org/micro/v3/tracer"
|
"go.unistack.org/micro/v4/tracer"
|
||||||
utildns "go.unistack.org/micro/v3/util/dns"
|
utildns "go.unistack.org/micro/v4/util/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -104,7 +104,6 @@ type service struct {
|
|||||||
done chan struct{}
|
done chan struct{}
|
||||||
opts Options
|
opts Options
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
stopped bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService creates and returns a new Service based on the packages within.
|
// NewService creates and returns a new Service based on the packages within.
|
||||||
@@ -430,7 +429,7 @@ func (s *service) Stop() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.notifyShutdown()
|
close(s.done)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -454,23 +453,10 @@ func (s *service) Run() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wait on context cancel
|
||||||
<-s.done
|
<-s.done
|
||||||
|
|
||||||
return nil
|
return s.Stop()
|
||||||
}
|
|
||||||
|
|
||||||
// notifyShutdown marks the service as stopped and closes the done channel.
|
|
||||||
// It ensures the channel is closed only once, preventing multiple closures.
|
|
||||||
func (s *service) notifyShutdown() {
|
|
||||||
s.Lock()
|
|
||||||
if s.stopped {
|
|
||||||
s.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.stopped = true
|
|
||||||
s.Unlock()
|
|
||||||
|
|
||||||
close(s.done)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Namer interface {
|
type Namer interface {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user