Skip to content

Commit

Permalink
Rename control components. (#704)
Browse files Browse the repository at this point in the history
1. Rename the control.Controller component to control.WeaverControl
   (to distinguish it from the DeployerControl component). Consistently
   rename corresponding types in other packages.
2. Introduce a control.DeployerControl component that will hold
   methods implemented by deployers. Remove the logger component
   and move LogBatch into control.DeployerControl.
3. Do not make the multi deployer provide a full component implementation
   (by using "weaver generate"). Instead, just export its override
   under the non-overridden component name.
  • Loading branch information
ghemawat authored Jan 8, 2024
1 parent 7ba5ecd commit 7c8a152
Show file tree
Hide file tree
Showing 14 changed files with 296 additions and 539 deletions.
66 changes: 0 additions & 66 deletions controller.go

This file was deleted.

31 changes: 15 additions & 16 deletions logger.go → deployerControl.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2023 Google LLC
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -19,36 +19,35 @@ import (
"fmt"
"os"

"github.com/ServiceWeaver/weaver/internal/control"
"github.com/ServiceWeaver/weaver/runtime/colors"
"github.com/ServiceWeaver/weaver/runtime/logging"
"github.com/ServiceWeaver/weaver/runtime/protos"
)

// Logger is a component used by the Service Weaver implementation for saving
// log entries. This component is overridden by various deployers to customize
// how logs are stored. The default implementation writes log entries to os.Stderr
// and is hosted in every weavelet.
type Logger interface {
LogBatch(context.Context, *protos.LogEntryBatch) error
}
// deployerControl is a component hosted in every deployer. Weavelets make calls to this
// component to interact with the deployer.
type deployerControl control.DeployerControl

type stderrLogger struct {
Implements[Logger]
// localDeployerControl is the implementation of deployerControl for local execution. It is
// overridden by remote deployers.
type localDeployerControl struct {
Implements[deployerControl]
pp *logging.PrettyPrinter
}

var _ Logger = &stderrLogger{}
var _ deployerControl = &localDeployerControl{}

// Init initializes the default Logger component.
func (logger *stderrLogger) Init(ctx context.Context) error {
logger.pp = logging.NewPrettyPrinter(colors.Enabled())
// Init initializes the local deployerControl component.
func (local *localDeployerControl) Init(ctx context.Context) error {
local.pp = logging.NewPrettyPrinter(colors.Enabled())
return nil
}

// LogBatch logs a list of entries.
func (logger *stderrLogger) LogBatch(ctx context.Context, batch *protos.LogEntryBatch) error {
func (local *localDeployerControl) LogBatch(ctx context.Context, batch *protos.LogEntryBatch) error {
for _, entry := range batch.Entries {
fmt.Fprintln(os.Stderr, logger.pp.Format(entry))
fmt.Fprintln(os.Stderr, local.pp.Format(entry))
}
return nil
}
5 changes: 1 addition & 4 deletions godeps.txt
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,10 @@ github.com/ServiceWeaver/weaver/internal/tool/multi
errors
flag
fmt
github.com/ServiceWeaver/weaver
github.com/ServiceWeaver/weaver/internal/control
github.com/ServiceWeaver/weaver/internal/metrics
github.com/ServiceWeaver/weaver/internal/must
github.com/ServiceWeaver/weaver/internal/proxy
github.com/ServiceWeaver/weaver/internal/reflection
github.com/ServiceWeaver/weaver/internal/routing
github.com/ServiceWeaver/weaver/internal/status
github.com/ServiceWeaver/weaver/internal/tool
Expand All @@ -576,8 +575,6 @@ github.com/ServiceWeaver/weaver/internal/tool/multi
github.com/ServiceWeaver/weaver/runtime/traces
github.com/ServiceWeaver/weaver/runtime/version
github.com/google/uuid
go.opentelemetry.io/otel/codes
go.opentelemetry.io/otel/trace
golang.org/x/exp/maps
golang.org/x/sync/errgroup
google.golang.org/protobuf/reflect/protoreflect
Expand Down
31 changes: 31 additions & 0 deletions internal/control/deployer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package control

import (
"context"

"github.com/ServiceWeaver/weaver/runtime/protos"
)

// DeployerControl is the interface for the weaver.deployerControl component. It is
// present in its own package so other packages do not need to copy the interface
// definition.
//
// Arguments and results are protobufs to allow deployers to evolve independently
// of application binaries.
type DeployerControl interface {
LogBatch(context.Context, *protos.LogEntryBatch) error
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ import (
"github.com/ServiceWeaver/weaver/runtime/protos"
)

// Controller is the interface for the weaver.controller component. It is present in
// its own package so other packages do not need to copy the interface definition.
// WeaveletControl is the interface for the weaver.weaveletControl component. It is
// present in its own package so other packages do not need to copy the interface
// definition.
//
// Arguments and results are protobufs to allow deployers to evolve independently of
// application binaries.
type Controller interface {
type WeaveletControl interface {
// UpdateComponents updates the weavelet with the latest set of components it
// should be running.
UpdateComponents(context.Context, *protos.UpdateComponentsRequest) (*protos.UpdateComponentsReply, error)
Expand Down
99 changes: 60 additions & 39 deletions internal/tool/multi/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,21 @@ import (
"log/slog"
"net"
"net/http"
"os"
"slices"
"sync"
"syscall"
"time"

"github.com/ServiceWeaver/weaver"
"github.com/ServiceWeaver/weaver/internal/control"
imetrics "github.com/ServiceWeaver/weaver/internal/metrics"
"github.com/ServiceWeaver/weaver/internal/proxy"
"github.com/ServiceWeaver/weaver/internal/reflection"
"github.com/ServiceWeaver/weaver/internal/routing"
"github.com/ServiceWeaver/weaver/internal/status"
"github.com/ServiceWeaver/weaver/internal/tool/certs"
"github.com/ServiceWeaver/weaver/runtime"
"github.com/ServiceWeaver/weaver/runtime/bin"
"github.com/ServiceWeaver/weaver/runtime/colors"
"github.com/ServiceWeaver/weaver/runtime/deployers"
"github.com/ServiceWeaver/weaver/runtime/envelope"
"github.com/ServiceWeaver/weaver/runtime/graph"
Expand All @@ -54,21 +55,25 @@ import (
// The default number of times a component is replicated.
const defaultReplication = 2

// Path name for the deployer control component we implement.
const deployerControlPath = "github.com/ServiceWeaver/weaver/deployerControl"

// A deployer manages an application deployment.
type deployer struct {
ctx context.Context
ctxCancel context.CancelFunc
deploymentId string
tmpDir string // Private directory for this weavelet/envelope
udsPath string // Path to Unix domain socket
config *MultiConfig
started time.Time
logger *slog.Logger
caCert *x509.Certificate
caKey crypto.PrivateKey
running errgroup.Group
loggerComponent *logger
traceDB *traces.DB
ctx context.Context
ctxCancel context.CancelFunc
deploymentId string
tmpDir string // Private directory for this weavelet/envelope
udsPath string // Path to Unix domain socket
config *MultiConfig
started time.Time
logger *slog.Logger
caCert *x509.Certificate
caKey crypto.PrivateKey
running errgroup.Group
logsDB *logging.FileStore
printer *logging.PrettyPrinter
traceDB *traces.DB

// statsProcessor tracks and computes stats to be rendered on the /statusz page.
statsProcessor *imetrics.StatsProcessor
Expand All @@ -80,6 +85,8 @@ type deployer struct {

}

var _ control.DeployerControl = &deployer{}

// A group contains information about a co-location group.
type group struct {
name string // group name
Expand Down Expand Up @@ -119,17 +126,15 @@ func newDeployer(ctx context.Context, deploymentId string, config *MultiConfig,
if err != nil {
return nil, fmt.Errorf("cannot create log storage: %w", err)
}
loggerComponent := newLogger(logsDB)
printer := logging.NewPrettyPrinter(colors.Enabled())
logger := slog.New(&logging.LogHandler{
Opts: logging.Options{
App: config.App.Name,
Component: "deployer",
Weavelet: uuid.NewString(),
Attrs: []string{"serviceweaver/system", ""},
},
// Local log entries are relayed directly to loggerComponent
// without going through any stubs.
Write: loggerComponent.log,
Write: func(e *protos.LogEntry) { log(logsDB, printer, e) },
})
var caCert *x509.Certificate
var caKey crypto.PrivateKey
Expand All @@ -155,20 +160,21 @@ func newDeployer(ctx context.Context, deploymentId string, config *MultiConfig,

ctx, cancel := context.WithCancel(ctx)
d := &deployer{
ctx: ctx,
ctxCancel: cancel,
tmpDir: tmpDir,
udsPath: udsPath,
logger: logger,
caCert: caCert,
caKey: caKey,
loggerComponent: loggerComponent,
traceDB: traceDB,
statsProcessor: imetrics.NewStatsProcessor(),
deploymentId: deploymentId,
config: config,
started: time.Now(),
proxies: map[string]*proxyInfo{},
ctx: ctx,
ctxCancel: cancel,
tmpDir: tmpDir,
udsPath: udsPath,
logger: logger,
caCert: caCert,
caKey: caKey,
logsDB: logsDB,
printer: printer,
traceDB: traceDB,
statsProcessor: imetrics.NewStatsProcessor(),
deploymentId: deploymentId,
config: config,
started: time.Now(),
proxies: map[string]*proxyInfo{},
}

// Form co-location groups.
Expand All @@ -191,10 +197,10 @@ func newDeployer(ctx context.Context, deploymentId string, config *MultiConfig,
return err
})

// Start a goroutine that serves calls to system components like multiLogger.
// Start a goroutine that serves calls to system components like deployerControl.
d.running.Go(func() error {
err := deployers.ServeComponents(d.ctx, uds, d.logger, map[string]any{
reflection.ComponentName[multiLogger](): loggerComponent,
deployerControlPath: d,
})
d.stop(err)
return err
Expand Down Expand Up @@ -350,10 +356,10 @@ func (d *deployer) startColocationGroup(g *group) error {
Mtls: d.config.Mtls,
InternalAddress: "localhost:0",
Redirects: []*protos.EnvelopeInfo_Redirect{
// Override the builtin logger.
// Supply custom deployer control component
{
Component: reflection.ComponentName[weaver.Logger](),
Target: reflection.ComponentName[multiLogger](),
Component: deployerControlPath,
Target: deployerControlPath,
Address: "unix://" + d.udsPath,
},
},
Expand Down Expand Up @@ -565,9 +571,17 @@ func (d *deployer) registerReplica(g *group, info *protos.WeaveletInfo, pid int)
return nil
}

// LogBatch implements the control.DeployerControl interface.
func (d *deployer) LogBatch(ctx context.Context, batch *protos.LogEntryBatch) error {
for _, entry := range batch.Entries {
log(d.logsDB, d.printer, entry)
}
return nil
}

// HandleLogEntry implements the envelope.EnvelopeHandler interface.
func (d *deployer) HandleLogEntry(_ context.Context, entry *protos.LogEntry) error {
d.loggerComponent.log(entry)
log(d.logsDB, d.printer, entry)
return nil
}

Expand Down Expand Up @@ -769,3 +783,10 @@ func runProfiling(_ context.Context, req *protos.GetProfileRequest, processes ma
data, err := profiling.ProfileGroups(groups)
return &protos.GetProfileReply{Data: data}, err
}

func log(db *logging.FileStore, printer *logging.PrettyPrinter, e *protos.LogEntry) {
if !logging.IsSystemGenerated(e) {
fmt.Fprintln(os.Stderr, printer.Format(e))
}
db.Add(e)
}
Loading

0 comments on commit 7c8a152

Please sign in to comment.