-
Notifications
You must be signed in to change notification settings - Fork 173
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
172 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2016-2017 VMware, Inc. All Rights Reserved. | ||
// | ||
// 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 vchlog | ||
|
||
import ( | ||
"bytes" | ||
"sync" | ||
"io" | ||
) | ||
|
||
// BufferedPipe struct implements a pipe readwriter with buffer | ||
// buffer: the internal buffer to hold data | ||
// c: the sync locker to manage concurrent reads and writes | ||
// closed: boolean indicating if the stream is closed | ||
type BufferedPipe struct { | ||
buffer *bytes.Buffer | ||
c *sync.Cond | ||
closed bool | ||
} | ||
|
||
// NewBufferedPipe returns a new buffered pipe instance | ||
// the internal buffer is initialized to default size. | ||
// Since internal memory is used, need to make sure that buffered data is bounded. | ||
func NewBufferedPipe() *BufferedPipe { | ||
var m sync.Mutex | ||
c := sync.NewCond(&m) | ||
return &BufferedPipe{ | ||
buffer: bytes.NewBuffer(nil), | ||
c: c, | ||
closed: false, | ||
} | ||
} | ||
|
||
// Read is blocked until a writer in the queue is done writing (until data is available) | ||
func (bp *BufferedPipe) Read(data []byte) (n int, err error) { | ||
bp.c.L.Lock() | ||
defer bp.c.L.Unlock() | ||
|
||
// pipe closed, drop all left-over data | ||
if bp.closed { | ||
return 0, io.EOF | ||
} | ||
for bp.buffer.Len() == 0 && !bp.closed { | ||
bp.c.Wait() | ||
} | ||
|
||
return bp.buffer.Read(data) | ||
} | ||
|
||
// Write writes to the internal buffer, and signals one of the reader in queue to start reading. | ||
func (bp *BufferedPipe) Write(data []byte) (n int, err error) { | ||
bp.c.L.Lock() | ||
defer bp.c.L.Unlock() | ||
defer bp.c.Signal() | ||
|
||
if bp.closed { | ||
return 0, io.ErrUnexpectedEOF | ||
} | ||
|
||
return bp.buffer.Write(data) | ||
} | ||
|
||
// Close closes the pipe. | ||
func (bp *BufferedPipe) Close() (err error) { | ||
bp.c.L.Lock() | ||
defer bp.c.L.Unlock() | ||
defer bp.c.Signal() | ||
bp.closed = true | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2016-2017 VMware, Inc. All Rights Reserved. | ||
// | ||
// 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 vchlog | ||
|
||
import ( | ||
"path" | ||
|
||
"github.com/vmware/govmomi/object" | ||
"github.com/vmware/vic/pkg/trace" | ||
) | ||
|
||
// DatastoreReadySignal serves as a signal struct indicating datastore folder path is available | ||
// Datastore: the govmomi datastore object | ||
// LogFileName: the filename of the destination path on datastore | ||
// Context: the caller context when sending the signal | ||
// VMPathName: the datastore path | ||
type DatastoreReadySignal struct { | ||
Datastore *object.Datastore | ||
LogFileName string | ||
Operation trace.Operation | ||
VMPathName string | ||
Timestamp string | ||
} | ||
|
||
// pipe: the streaming readwriter pipe to hold log messages | ||
var pipe *BufferedPipe | ||
|
||
// signalChan: channel for signaling when datastore folder is ready | ||
var signalChan chan DatastoreReadySignal | ||
|
||
// Init initializes the logger, creates the streaming pipe and makes the singaling channel. | ||
func Init() { | ||
pipe = NewBufferedPipe() | ||
signalChan = make(chan DatastoreReadySignal) | ||
} | ||
|
||
// Run waits until the signal arrives and uploads the streaming pipe to datastore | ||
func Run() { | ||
sig := <-signalChan | ||
// suffix the log file name with caller operation ID and timestamp | ||
logFileName := sig.LogFileName + "_time_" + sig.Timestamp + "_op_" + sig.Operation.ID() | ||
sig.Datastore.Upload(sig.Operation.Context, pipe, path.Join(sig.VMPathName, logFileName), nil) | ||
} | ||
|
||
// GetPipe returns the streaming pipe of the vch logger | ||
func GetPipe() *BufferedPipe { | ||
return pipe | ||
} | ||
|
||
// Signal signals the logger that the datastore folder is ready | ||
func Signal(sig DatastoreReadySignal) { | ||
signalChan <- sig | ||
} | ||
|
||
// Close stops the logger by closing the underlying pipe | ||
func Close() { | ||
pipe.Close() | ||
} |