Merge pull request #3 from GoogleCloudPlatform/master

Merge from upstream
This commit is contained in:
Colin Nelson 2018-09-26 07:26:17 -07:00 committed by GitHub
commit ddddf6519b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 244 additions and 90 deletions

View file

@ -1,7 +1,6 @@
# cartservice_probe
FROM golang:1.10 as builder
FROM golang:1.10 as probe
RUN wget -qO/go/bin/dep https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 && \
chmod +x /go/bin/dep
chmod +x /go/bin/dep
ENV PROJECT github.com/GoogleCloudPlatform/microservices-demo/src/cartservice/probe
WORKDIR /go/src/$PROJECT
COPY probe/Gopkg.* ./
@ -9,14 +8,28 @@ RUN dep ensure --vendor-only -v
COPY ./probe ./
RUN go build -o /cartservice_probe .
# cartservice
FROM gcr.io/google-appengine/aspnetcore:2.1.0
COPY --from=builder /cartservice_probe /cartservice_probe
RUN apt-get update && apt-get install net-tools telnet
FROM microsoft/dotnet:2.1-sdk-alpine as builder
WORKDIR /app
COPY . .
RUN dotnet restore && \
dotnet build && \
dotnet publish
WORKDIR /app/bin/Debug/netcoreapp2.0
ENTRYPOINT ["dotnet", "cartservice.dll", "start"]
dotnet publish -c release -r linux-musl-x64 -o /cartservice
# cartservice
FROM alpine:3.8
# Add the probe
COPY --from=probe /cartservice_probe /cartservice_probe
# Dependencies for runtime
# busybox-extras => telnet
RUN apk add --no-cache \
busybox-extras \
libc6-compat \
libunwind \
libuuid \
libgcc \
libstdc++ \
libintl \
icu
WORKDIR /app
COPY --from=builder /cartservice .
ENTRYPOINT ["./cartservice", "start"]

View file

@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>

View file

@ -56,6 +56,14 @@
revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f"
version = "v2.0.0"
[[projects]]
digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
version = "v1.0.6"
[[projects]]
name = "go.opencensus.io"
packages = [
@ -77,6 +85,14 @@
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
[[projects]]
branch = "master"
name = "golang.org/x/net"

View file

@ -41,6 +41,10 @@
name = "github.com/google/uuid"
version = "1.0.0"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.6"
[[constraint]]
name = "go.opencensus.io"
version = "0.16.0"

View file

@ -17,7 +17,6 @@ package main
import (
"context"
"fmt"
"log"
"net"
"os"
"time"
@ -25,6 +24,7 @@ import (
"cloud.google.com/go/profiler"
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
@ -42,6 +42,22 @@ const (
usdCurrency = "USD"
)
var log *logrus.Logger
func init() {
log = logrus.New()
log.Level = logrus.DebugLevel
log.Formatter = &logrus.JSONFormatter{
FieldMap: logrus.FieldMap{
logrus.FieldKeyTime: "timestamp",
logrus.FieldKeyLevel: "severity",
logrus.FieldKeyMsg: "message",
},
TimestampFormat: time.RFC3339Nano,
}
log.Out = os.Stdout
}
type checkoutService struct {
productCatalogSvcAddr string
cartSvcAddr string
@ -68,7 +84,7 @@ func main() {
mustMapEnv(&svc.emailSvcAddr, "EMAIL_SERVICE_ADDR")
mustMapEnv(&svc.paymentSvcAddr, "PAYMENT_SERVICE_ADDR")
log.Printf("service config: %+v", svc)
log.Infof("service config: %+v", svc)
lis, err := net.Listen("tcp", fmt.Sprintf(":%s", port))
if err != nil {
@ -77,16 +93,17 @@ func main() {
srv := grpc.NewServer(grpc.StatsHandler(&ocgrpc.ServerHandler{}))
pb.RegisterCheckoutServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, svc)
log.Printf("starting to listen on tcp: %q", lis.Addr().String())
log.Fatal(srv.Serve(lis))
log.Infof("starting to listen on tcp: %q", lis.Addr().String())
err = srv.Serve(lis)
log.Fatal(err)
}
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
log.Warn("Error registering default server views")
} else {
log.Printf("Registered default server views")
log.Info("Registered default server views")
}
}
@ -96,21 +113,21 @@ func initTracing() {
for i := 1; i <= 3; i++ {
exporter, err := stackdriver.NewExporter(stackdriver.Options{})
if err != nil {
log.Printf("info: failed to initialize stackdriver exporter: %+v", err)
log.Infof("failed to initialize stackdriver exporter: %+v", err)
} else {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
log.Info("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver exporter", d)
log.Infof("sleeping %v to retry initializing stackdriver exporter", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up")
log.Warn("could not initialize stackdriver exporter after retrying, giving up")
}
func initProfiling(service, version string) {
@ -123,16 +140,16 @@ func initProfiling(service, version string) {
// ProjectID must be set if not running on GCP.
// ProjectID: "my-project",
}); err != nil {
log.Printf("warn: failed to start profiler: %+v", err)
log.Warnf("failed to start profiler: %+v", err)
} else {
log.Print("started stackdriver profiler")
log.Info("started stackdriver profiler")
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver profiler", d)
log.Infof("sleeping %v to retry initializing stackdriver profiler", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up")
log.Warn("could not initialize stackdriver profiler after retrying, giving up")
}
func mustMapEnv(target *string, envKey string) {
@ -148,7 +165,7 @@ func (cs *checkoutService) Check(ctx context.Context, req *healthpb.HealthCheckR
}
func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderRequest) (*pb.PlaceOrderResponse, error) {
log.Printf("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency)
log.Infof("[PlaceOrder] user_id=%q user_currency=%q", req.UserId, req.UserCurrency)
orderID, err := uuid.NewUUID()
if err != nil {
@ -172,7 +189,7 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to charge card: %+v", err)
}
log.Printf("payment went through (transaction_id: %s)", txID)
log.Infof("payment went through (transaction_id: %s)", txID)
shippingTrackingID, err := cs.shipOrder(ctx, req.Address, prep.cartItems)
if err != nil {
@ -190,9 +207,9 @@ func (cs *checkoutService) PlaceOrder(ctx context.Context, req *pb.PlaceOrderReq
}
if err := cs.sendOrderConfirmation(ctx, req.Email, orderResult); err != nil {
log.Printf("failed to send order confirmation to %q: %+v", req.Email, err)
log.Warnf("failed to send order confirmation to %q: %+v", req.Email, err)
} else {
log.Printf("order confirmation email sent to %q", req.Email)
log.Infof("order confirmation email sent to %q", req.Email)
}
resp := &pb.PlaceOrderResponse{Order: orderResult}
return resp, nil

View file

@ -1,27 +1,45 @@
FROM python:3-alpine as base
FROM base as builder
# Use the grpc.io provided Python image as the base image
FROM grpc/python:1.0
# gRPC and app deps
RUN apk add --update --no-cache \
gcc \
linux-headers \
make \
musl-dev \
python-dev \
g++ \
# App Deps
cairo-dev \
cairo \
openssl-dev \
gobject-introspection-dev
# download the grpc health probe
# get packages
COPY requirements.txt .
RUN pip install -r requirements.txt
FROM base as final
# Enable unbuffered logging
ENV PYTHONUNBUFFERED=1
# Download the grpc health probe
RUN GRPC_HEALTH_PROBE_VERSION=v0.1.0-alpha.1 && \
wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
chmod +x /bin/grpc_health_probe
# show python logs as they occur
ENV PYTHONUNBUFFERED=0
# install pip for python3
RUN apt-get -qqy update && \
apt-get -qqy install python3-pip
# get packages
WORKDIR /email_server
COPY requirements.txt .
RUN pip3 install -r requirements.txt
# Grab packages from builder
COPY --from=builder /usr/local/lib/python3.7/ /usr/local/lib/python3.7/
# Need libstdc++ for grpc
RUN apk add --no-cache libstdc++
# Add the application
COPY . .
EXPOSE 8080
ENTRYPOINT [ "python3", "email_server.py" ]
ENTRYPOINT [ "python", "email_server.py" ]

View file

@ -1,31 +1,41 @@
asn1crypto==0.24.0
cachetools==2.1.0
certifi==2018.4.16
certifi==2018.8.24
cffi==1.11.5
chardet==3.0.4
cryptography==1.7.1
google-api-core==1.2.1
google-auth==1.5.0
configparser==3.5.0
cryptography==2.3.1
entrypoints==0.2.3
enum34==1.1.6
futures==3.1.1
google-api-core==1.4.0
google-auth==1.5.1
google-cloud-core==0.28.1
google-cloud-trace==0.19.0
googleapis-common-protos==1.5.3
grpc-google-iam-v1==0.11.4
grpcio==1.12.1
grpcio-health-checking==1.14.1
grpcio-health-checking==1.12.1
grpcio-tools==1.12.1
idna==2.7
ipaddress==1.0.22
jeepney==0.4
Jinja2==2.10
keyring==10.1
keyrings.alt==1.3
keyring==15.1.0
keyrings.alt==3.1
MarkupSafe==1.0
opencensus==0.1.5
protobuf==3.6.0
pyasn1==0.4.3
opencensus==0.1.7
protobuf==3.6.1
pyasn1==0.4.4
pyasn1-modules==0.2.2
pycairo==1.17.1
pycparser==2.19
pycrypto==2.6.1
pygobject==3.22.0
PyGObject==3.30.1
pytz==2018.5
pyxdg==0.25
pyxdg==0.26
requests==2.19.1
rsa==3.4.2
SecretStorage==2.3.1
rsa==4.0
SecretStorage==3.1.0
six==1.11.0
urllib3==1.23
urllib3==1.23

View file

@ -83,7 +83,15 @@ func main() {
ctx := context.Background()
log := logrus.New()
log.Level = logrus.DebugLevel
log.Formatter = &logrus.TextFormatter{}
log.Formatter = &logrus.JSONFormatter{
FieldMap: logrus.FieldMap{
logrus.FieldKeyTime: "timestamp",
logrus.FieldKeyLevel: "severity",
logrus.FieldKeyMsg: "message",
},
TimestampFormat: time.RFC3339Nano,
}
log.Out = os.Stdout
go initProfiling(log, "frontend", "1.0.0")
go initTracing(log)

View file

@ -62,6 +62,14 @@
revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f"
version = "v2.0.0"
[[projects]]
digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
version = "v1.0.6"
[[projects]]
name = "go.opencensus.io"
packages = [
@ -83,6 +91,14 @@
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
[[projects]]
branch = "master"
name = "golang.org/x/net"

View file

@ -41,6 +41,10 @@
name = "github.com/google/go-cmp"
version = "0.2.0"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.6"
[[constraint]]
name = "go.opencensus.io"
version = "0.16.0"

View file

@ -20,8 +20,8 @@ import (
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"os"
"strings"
"time"
@ -31,6 +31,7 @@ import (
"cloud.google.com/go/profiler"
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/golang/protobuf/jsonpb"
"github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
@ -41,6 +42,7 @@ import (
var (
catalogJSON []byte
log *logrus.Logger
port = flag.Int("port", 3550, "port to listen at")
)
@ -51,7 +53,17 @@ func init() {
log.Fatalf("failed to open product catalog json file: %v", err)
}
catalogJSON = c
log.Printf("successfully parsed product catalog json")
log = logrus.New()
log.Formatter = &logrus.JSONFormatter{
FieldMap: logrus.FieldMap{
logrus.FieldKeyTime: "timestamp",
logrus.FieldKeyLevel: "severity",
logrus.FieldKeyMsg: "message",
},
TimestampFormat: time.RFC3339Nano,
}
log.Out = os.Stdout
log.Info("successfully parsed product catalog json")
}
func main() {
@ -59,7 +71,7 @@ func main() {
go initProfiling("productcatalogservice", "1.0.0")
flag.Parse()
log.Printf("starting grpc server at :%d", *port)
log.Infof("starting grpc server at :%d", *port)
run(*port)
select {}
}
@ -80,9 +92,9 @@ func run(port int) string {
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
log.Info("Error registering default server views")
} else {
log.Printf("Registered default server views")
log.Info("Registered default server views")
}
}
@ -92,21 +104,21 @@ func initTracing() {
for i := 1; i <= 3; i++ {
exporter, err := stackdriver.NewExporter(stackdriver.Options{})
if err != nil {
log.Printf("info: failed to initialize stackdriver exporter: %+v", err)
log.Warnf("failed to initialize stackdriver exporter: %+v", err)
} else {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
log.Info("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver exporter", d)
log.Infof("sleeping %v to retry initializing stackdriver exporter", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up")
log.Warn("could not initialize stackdriver exporter after retrying, giving up")
}
func initProfiling(service, version string) {
@ -119,16 +131,16 @@ func initProfiling(service, version string) {
// ProjectID must be set if not running on GCP.
// ProjectID: "my-project",
}); err != nil {
log.Printf("warn: failed to start profiler: %+v", err)
log.Warnf("failed to start profiler: %+v", err)
} else {
log.Print("started stackdriver profiler")
log.Info("started stackdriver profiler")
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver profiler", d)
log.Infof("sleeping %v to retry initializing stackdriver profiler", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up")
log.Warn("could not initialize stackdriver profiler after retrying, giving up")
}
type productCatalog struct{}
@ -137,7 +149,7 @@ func parseCatalog() []*pb.Product {
var cat pb.ListProductsResponse
if err := jsonpb.Unmarshal(bytes.NewReader(catalogJSON), &cat); err != nil {
log.Printf("warning: failed to parse the catalog JSON: %v", err)
log.Warnf("failed to parse the catalog JSON: %v", err)
return nil
}
return cat.Products

View file

@ -50,6 +50,14 @@
revision = "317e0006254c44a0ac427cc52a0e083ff0b9622f"
version = "v2.0.0"
[[projects]]
digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc"
name = "github.com/sirupsen/logrus"
packages = ["."]
pruneopts = "UT"
revision = "3e01752db0189b9157070a0e1668a620f9a85da2"
version = "v1.0.6"
[[projects]]
name = "go.opencensus.io"
packages = [
@ -71,6 +79,14 @@
revision = "b11f239c032624b045c4c2bfd3d1287b4012ce89"
version = "v0.16.0"
[[projects]]
branch = "master"
digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
name = "golang.org/x/crypto"
packages = ["ssh/terminal"]
pruneopts = "UT"
revision = "0e37d006457bf46f9e6692014ba72ef82c33022c"
[[projects]]
branch = "master"
name = "golang.org/x/net"

View file

@ -37,6 +37,10 @@
name = "github.com/golang/protobuf"
version = "1.2.0"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.6"
[[constraint]]
name = "go.opencensus.io"
version = "0.16.0"

View file

@ -16,13 +16,13 @@ package main
import (
"fmt"
"log"
"net"
"os"
"time"
"cloud.google.com/go/profiler"
"contrib.go.opencensus.io/exporter/stackdriver"
"github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
@ -38,6 +38,22 @@ const (
defaultPort = "50051"
)
var log *logrus.Logger
func init() {
log = logrus.New()
log.Level = logrus.DebugLevel
log.Formatter = &logrus.JSONFormatter{
FieldMap: logrus.FieldMap{
logrus.FieldKeyTime: "timestamp",
logrus.FieldKeyLevel: "severity",
logrus.FieldKeyMsg: "message",
},
TimestampFormat: time.RFC3339Nano,
}
log.Out = os.Stdout
}
func main() {
go initTracing()
go initProfiling("shippingservice", "1.0.0")
@ -56,7 +72,7 @@ func main() {
svc := &server{}
pb.RegisterShippingServiceServer(srv, svc)
healthpb.RegisterHealthServer(srv, svc)
log.Printf("Shipping Service listening on port %s", port)
log.Infof("Shipping Service listening on port %s", port)
// Register reflection service on gRPC server.
reflection.Register(srv)
@ -75,8 +91,8 @@ func (s *server) Check(ctx context.Context, req *healthpb.HealthCheckRequest) (*
// GetQuote produces a shipping quote (cost) in USD.
func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQuoteResponse, error) {
log.Printf("[GetQuote] received request")
defer log.Printf("[GetQuote] completed request")
log.Info("[GetQuote] received request")
defer log.Info("[GetQuote] completed request")
// 1. Our quote system requires the total number of items to be shipped.
count := 0
@ -100,8 +116,8 @@ func (s *server) GetQuote(ctx context.Context, in *pb.GetQuoteRequest) (*pb.GetQ
// ShipOrder mocks that the requested items will be shipped.
// It supplies a tracking ID for notional lookup of shipment delivery status.
func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.ShipOrderResponse, error) {
log.Printf("[ShipOrder] received request")
defer log.Printf("[ShipOrder] completed request")
log.Info("[ShipOrder] received request")
defer log.Info("[ShipOrder] completed request")
// 1. Create a Tracking ID
baseAddress := fmt.Sprintf("%s, %s, %s", in.Address.StreetAddress, in.Address.City, in.Address.State)
id := CreateTrackingId(baseAddress)
@ -115,9 +131,9 @@ func (s *server) ShipOrder(ctx context.Context, in *pb.ShipOrderRequest) (*pb.Sh
func initStats(exporter *stackdriver.Exporter) {
view.RegisterExporter(exporter)
if err := view.Register(ocgrpc.DefaultServerViews...); err != nil {
log.Printf("Error registering default server views")
log.Warn("Error registering default server views")
} else {
log.Printf("Registered default server views")
log.Info("Registered default server views")
}
}
@ -127,21 +143,21 @@ func initTracing() {
for i := 1; i <= 3; i++ {
exporter, err := stackdriver.NewExporter(stackdriver.Options{})
if err != nil {
log.Printf("info: failed to initialize stackdriver exporter: %+v", err)
log.Warnf("failed to initialize stackdriver exporter: %+v", err)
} else {
trace.RegisterExporter(exporter)
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
log.Print("registered stackdriver tracing")
log.Info("registered stackdriver tracing")
// Register the views to collect server stats.
initStats(exporter)
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver exporter", d)
log.Infof("sleeping %v to retry initializing stackdriver exporter", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver exporter after retrying, giving up")
log.Warn("could not initialize stackdriver exporter after retrying, giving up")
}
func initProfiling(service, version string) {
@ -154,14 +170,14 @@ func initProfiling(service, version string) {
// ProjectID must be set if not running on GCP.
// ProjectID: "my-project",
}); err != nil {
log.Printf("warn: failed to start profiler: %+v", err)
log.Warnf("failed to start profiler: %+v", err)
} else {
log.Print("started stackdriver profiler")
log.Info("started stackdriver profiler")
return
}
d := time.Second * 10 * time.Duration(i)
log.Printf("sleeping %v to retry initializing stackdriver profiler", d)
log.Infof("sleeping %v to retry initializing stackdriver profiler", d)
time.Sleep(d)
}
log.Printf("warning: could not initialize stackdriver profiler after retrying, giving up")
log.Warn("could not initialize stackdriver profiler after retrying, giving up")
}

View file

@ -50,6 +50,6 @@ func quoteByCountFloat(count int) float64 {
return 0
}
count64 := float64(count)
var p float64 = 1 + (count64 * 0.2)
var p = 1 + (count64 * 0.2)
return count64 + math.Pow(3, p)
}