Skip to content

Commit

Permalink
encapsulate the variables needed for the openCensus framework (census…
Browse files Browse the repository at this point in the history
…-ecosystem#49)

* encapsulate the basic variables needed by the openCensus framework into a struct and implement the its API
  • Loading branch information
peiqinzhao authored Jul 18, 2018
1 parent 0e3dd9f commit d16eef7
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 20 deletions.
10 changes: 6 additions & 4 deletions go/iot/protocol/doc/protocol.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ After the registration, the Raspberry Pi would make a response to the record req

Typical example for the response by Raspberry Pi would be as below:
{
"Code": 200 or 404 or 501
"Code": 200 or 404 or 501 or 502
"Info": "Record Successfully!" or "Registration Not Finished" or ...
}

Expand All @@ -49,14 +49,16 @@ In the following cases Pi would make response with the Code 404:

In the following case Pi would make response with the Code 501:
1. The measure doesn't bind to any views.
In this case, the Pi would ignore the request.

In the following case Pi would make response with the Code 502:
1. The tag keys in the data request don't bind to any views.
In this case, the Pi would record the data without tag key/value.

When the Pi parses and records data successfully, it would make response with the Code 200.

However, in the following corner cases Pi would still respond with Code 200:
1. The tag keys in the data request don't bind to any views.
In this case, the Pi would record the data without tag key/value.
2. The exporter could not work normally such as the backend server crashes.
1. The exporter could not work normally such as the backend server crashes.
In this case, the Pi would record the data and respond positively.


Expand Down
13 changes: 6 additions & 7 deletions go/iot/protocol/examples/arduino/protocol.ino
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
// limitations under the License.
//
// This program shows how to send requests of registration and sending data to the raspberry Pi based on the protocols.
/*
Hardware Connections (Breakoutboard to Arduino):
-VCC = 3.3V
-GND = GND
-SDA = A4 (use inline 330 ohm resistor if your board is 5V)
-SCL = A5 (use inline 330 ohm resistor if your board is 5V)
*/
//
// Hardware Connections (Breakoutboard to Arduino):
// -VCC = 3.3V
// -GND = GND
// -SDA = A4 (use inline 330 ohm resistor if your board is 5V)
// -SCL = A5 (use inline 330 ohm resistor if your board is 5V)

#include <ArduinoJson.h>

Expand Down
142 changes: 142 additions & 0 deletions go/iot/protocol/opencensus/opencensus_base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2018, OpenCensus Authors
//
// 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 opencensus

import (
"context"
"log"
"strconv"
"time"

"contrib.go.opencensus.io/exporter/stackdriver"
"fmt"
"github.com/census-ecosystem/opencensus-experiments/go/iot/protocol"
"github.com/pkg/errors"
"go.opencensus.io/stats"
"go.opencensus.io/stats/view"
"go.opencensus.io/tag"
)

type OpenCensusBase struct {
ctx context.Context
registeredMeasures map[string]stats.Measure // Store all the measure based on their Name. Used for the future record
// TODO: What if different views share the same tag key
registeredTagKeys map[string]tag.Key
}

func (census *OpenCensusBase) Initialize(projectId string, reportPeriod int) {
census.ctx = context.Background()
census.registeredMeasures = make(map[string]stats.Measure)
census.registeredTagKeys = make(map[string]tag.Key)
exporter, err := stackdriver.NewExporter(stackdriver.Options{
ProjectID: projectId, // Google Cloud Console project ID.
})
if err != nil {
log.Fatal(err)
}
view.RegisterExporter(exporter)
view.SetReportingPeriod(time.Second * time.Duration(reportPeriod))
}

func (census *OpenCensusBase) containsMeasure(name string) bool {
_, ok := census.registeredMeasures[name]
return ok
}

func (census *OpenCensusBase) isMeasureConflict(measure *stats.Measure) bool {
var myMeasure = census.registeredMeasures[(*measure).Name()]
if myMeasure.Description() != (*measure).Description() || myMeasure.Unit() != (*measure).Unit() {
return true
}
return false
}

// Given the censusArgument, initialize the OpenCensus framework
func (census *OpenCensusBase) ViewRegistration(myView *(view.View)) error {
// The view has never been registered before.
if err := view.Register(myView); err != nil {
return err
} else {
if census.containsMeasure(myView.Measure.Name()) {
if flag := census.isMeasureConflict(&myView.Measure); flag == true {
return errors.Errorf("Different measures share the same name!")
}
} else {
census.registeredMeasures[myView.Measure.Name()] = myView.Measure
}
// Store the tag name
var tagKeys = myView.TagKeys
for _, key := range tagKeys {
census.registeredTagKeys[key.Name()] = key
}
}
return nil
}

func (census *OpenCensusBase) insertTag(tagPairs map[string]string) (context.Context, bool, error) {
// Insert tag values to the context if it exists
// Normally the program returns the context and nil error
// But when any tag key doesn't exist, we still return the context but don't insert that tag key
var mutators []tag.Mutator
var tagExist = true
for key, value := range tagPairs {
tagKey, ok := census.registeredTagKeys[key]
if ok == true {
// The tag key exists
mutators = append(mutators, tag.Insert(tagKey, value))
} else {
tagExist = false
}
}
ctx, err := tag.New(census.ctx,
mutators...,
)
return ctx, tagExist, err
}
func (census *OpenCensusBase) Record(arguments *protocol.MeasureArgument) *protocol.Response {
measureName := arguments.Name
if census.containsMeasure(measureName) == false {
return &protocol.Response{protocol.UNREGISTERMEASURE, "Measure is not registered"}
} else {
measure := census.registeredMeasures[measureName]

ctx, tagExist, err := census.insertTag(arguments.Tags)

if err != nil {
return &protocol.Response{protocol.FAIL, err.Error()}
}

if value, err := strconv.ParseFloat(arguments.Value, 64); err != nil {
info := fmt.Sprintf("Could not parse the value: %s because %s", arguments.Value, err.Error())
return &protocol.Response{protocol.FAIL, info}
} else {
//log.Printf("Record Data %v", value)
switch vv := measure.(type) {
case *stats.Float64Measure:
stats.Record(ctx, vv.M(float64(value)))
case *stats.Int64Measure:
stats.Record(ctx, vv.M(int64(value)))
default:
return &protocol.Response{protocol.FAIL, "Unsupported measure type"}
}
}

if tagExist {
return &protocol.Response{protocol.OK, nil}
} else {
return &protocol.Response{protocol.UNREGISTERTAG, "Tags key doesn't exist."}
}
}
}
33 changes: 33 additions & 0 deletions go/iot/protocol/protocol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2018, OpenCensus Authors
//
// 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 protocol

const (
OK = 200
FAIL = 404
UNREGISTERTAG = 501
UNREGISTERMEASURE = 502
)

type MeasureArgument struct {
Name string
Value string
Tags map[string]string
}

type Response struct {
Code int
Info string
}
16 changes: 7 additions & 9 deletions go/iot/sensor/examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var (
viewSoundDist = &view.View{
Name: "opencensus.io/views/sound_strength_distribution",
Description: "sound strength distribution over time",
Measure: soundStrengthDistMeasure,
Measure: soundStrengthMeasure,
Aggregation: view.Distribution(0, 2, 4, 8, 16, 32, 64, 128),
}

Expand All @@ -53,7 +53,7 @@ var (
viewSoundLast = &view.View{
Name: "opencensus.io/views/sound_strength_instant",
Description: "sound strength instantly over time",
Measure: soundStrengthLastMeasure,
Measure: soundStrengthMeasure,
Aggregation: view.LastValue(),
}

Expand Down Expand Up @@ -90,11 +90,10 @@ var (
}

// Apply two kinds of aggregation type to the same metric in order to see the difference.
soundStrengthDistMeasure = stats.Int64("opencensus.io/measure/sound_strength_svl_mp1_7c3c_dist", "strength of sound", stats.UnitDimensionless)
soundStrengthLastMeasure = stats.Int64("opencensus.io/measure/sound_strength_svl_mp1_7c3c_last", "strength of sound", stats.UnitDimensionless)
lightStrengthMeasure = stats.Int64("opencensus.io/measure/light_strength_svl_mp1_7c3c", "strength of light", stats.UnitDimensionless)
humidityMeasure = stats.Float64("opencensus.io/measure/humidity_svl_mp1_7c3c", "humidity", stats.UnitDimensionless)
temperatureMeasure = stats.Float64("opencensus.io/measure/temperature_svl_mp1_7c3c", "temperature", stats.UnitDimensionless)
soundStrengthMeasure = stats.Int64("opencensus.io/measure/sound_strength_svl_mp1_7c3c", "strength of sound", stats.UnitDimensionless)
lightStrengthMeasure = stats.Int64("opencensus.io/measure/light_strength_svl_mp1_7c3c", "strength of light", stats.UnitDimensionless)
humidityMeasure = stats.Float64("opencensus.io/measure/humidity_svl_mp1_7c3c", "humidity", stats.UnitDimensionless)
temperatureMeasure = stats.Float64("opencensus.io/measure/temperature_svl_mp1_7c3c", "temperature", stats.UnitDimensionless)

soundSamplePeriod = 50 * time.Millisecond
temperatureSamplePeriod = 5 * time.Second
Expand Down Expand Up @@ -158,8 +157,7 @@ func recordSound(ctx context.Context, soundSensor *aio.GroveSoundSensorDriver) {
if soundErr != nil {
log.Fatalf("Could not read value from sound sensors\n")
} else {
stats.Record(ctx, soundStrengthDistMeasure.M(int64(soundStrength)))
stats.Record(ctx, soundStrengthLastMeasure.M(int64(soundStrength)))
stats.Record(ctx, soundStrengthMeasure.M(int64(soundStrength)))
//log.Printf("Sound Strength: %d\n", soundStrength)
}
}
Expand Down

0 comments on commit d16eef7

Please sign in to comment.