Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vtrack and event endpoints #1467

Merged
merged 37 commits into from
Oct 8, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5427a8d
vtrack endpoint
danielguedesb Aug 27, 2020
c3266b7
vtrack endpoint
danielguedesb Aug 27, 2020
33b8986
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Aug 27, 2020
4d0d52e
event endpoint
danielguedesb Aug 31, 2020
bf22735
omit empty fields
danielguedesb Sep 1, 2020
14a2f6d
refactor
danielguedesb Sep 1, 2020
3caccd6
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 1, 2020
adf7d54
refactor
danielguedesb Sep 1, 2020
288ea60
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 4, 2020
456626a
PR 1467
danielguedesb Sep 6, 2020
cb2003e
Use time.Time instead of int64 for NotificationEvent Timestamp
danielguedesb Sep 6, 2020
31ee2ae
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 8, 2020
65203d6
PR-1467
danielguedesb Sep 9, 2020
c695811
PR-1467 - handle test errors
danielguedesb Sep 9, 2020
6a7ec84
PR-1467 - feedback
danielguedesb Sep 9, 2020
065832d
PR-1467
danielguedesb Sep 10, 2020
7ce0ca1
PR-1467
danielguedesb Sep 11, 2020
aa6f2ac
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 11, 2020
8a9415d
Keep trackingPixel object local
danielguedesb Sep 12, 2020
dd25a92
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 14, 2020
560b854
Leverage #1483 to replace current account fetching logic
danielguedesb Sep 15, 2020
c000874
Refactor HandleAccountServiceErrors func
danielguedesb Sep 16, 2020
4eb434d
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 21, 2020
9c2d786
Report all errors found when parsing event request
danielguedesb Sep 21, 2020
6c29f99
PR #1467 Feedback
danielguedesb Sep 23, 2020
fab32ca
PR #1467 Feedback
danielguedesb Sep 24, 2020
2894519
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 29, 2020
b5143e6
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Sep 30, 2020
2a74429
PR #1467 Feedback
danielguedesb Sep 30, 2020
4432c6f
trigger GitHub actions
danielguedesb Sep 30, 2020
3c72bc1
Merge branch 'master' of https://github.com/prebid/prebid-server into…
danielguedesb Oct 2, 2020
264f384
PR #1467 Feedback
danielguedesb Oct 2, 2020
5a8d756
refactor events.HandleAccountServiceErrors
danielguedesb Oct 2, 2020
a8bcfa6
#1467 feedback
danielguedesb Oct 5, 2020
b1a77d1
#1467 feedback
danielguedesb Oct 6, 2020
7bccb7c
#1467 feedback
danielguedesb Oct 6, 2020
a32d642
sync with master
danielguedesb Oct 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions adapters/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,11 @@ const (
)

type BidderInfo struct {
Status BidderStatus `yaml:"status" json:"status"`
Maintainer *MaintainerInfo `yaml:"maintainer" json:"maintainer"`
Capabilities *CapabilitiesInfo `yaml:"capabilities" json:"capabilities"`
AliasOf string `json:"aliasOf,omitempty"`
Status BidderStatus `yaml:"status" json:"status"`
Maintainer *MaintainerInfo `yaml:"maintainer" json:"maintainer"`
Capabilities *CapabilitiesInfo `yaml:"capabilities" json:"capabilities"`
AliasOf string `json:"aliasOf,omitempty"`
ModifyingVastXmlAllowed bool `yaml:"modifyingVastXmlAllowed" json:"-" xml:"-"`
}

type MaintainerInfo struct {
Expand Down
6 changes: 6 additions & 0 deletions analytics/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,9 @@ func (ea enabledAnalytics) LogAmpObject(ao *analytics.AmpObject) {
module.LogAmpObject(ao)
}
}

func (ea enabledAnalytics) LogNotificationEventObject(ne *analytics.NotificationEvent) {
for _, module := range ea {
module.LogNotificationEventObject(ne)
}
}
7 changes: 7 additions & 0 deletions analytics/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func TestSampleModule(t *testing.T) {
if count != 5 {
t.Errorf("PBSAnalyticsModule failed at LogVideoObject")
}

am.LogNotificationEventObject(&analytics.NotificationEvent{})
if count != 6 {
t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject")
}
}

type sampleModule struct {
Expand All @@ -67,6 +72,8 @@ func (m *sampleModule) LogSetUIDObject(so *analytics.SetUIDObject) { *m.count++

func (m *sampleModule) LogAmpObject(ao *analytics.AmpObject) { *m.count++ }

func (m *sampleModule) LogNotificationEventObject(ne *analytics.NotificationEvent) { *m.count++ }

func initAnalytics(count *int) analytics.PBSAnalyticsModule {
modules := make(enabledAnalytics, 0)
modules = append(modules, &sampleModule{count})
Expand Down
11 changes: 11 additions & 0 deletions analytics/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/prebid/prebid-server/usersync"
"time"
)

/*
Expand All @@ -21,6 +22,7 @@ type PBSAnalyticsModule interface {
LogCookieSyncObject(*CookieSyncObject)
LogSetUIDObject(*SetUIDObject)
LogAmpObject(*AmpObject)
LogNotificationEventObject(*NotificationEvent)
}

//Loggable object of a transaction at /openrtb2/auction endpoint
Expand Down Expand Up @@ -67,3 +69,12 @@ type CookieSyncObject struct {
Errors []error
BidderStatus []*usersync.CookieSyncBidders
}

// NotificationEvent is a loggable object
type NotificationEvent struct {
Type string `json:"type"`
Bidid string `json:"bidid"`
Account *config.Account `json:"account"`
Bidder string `json:"bidder"`
Timestamp time.Time `json:"timestamp"`
}
40 changes: 35 additions & 5 deletions analytics/filesystem/file_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (
type RequestType string

const (
COOKIE_SYNC RequestType = "/cookie_sync"
AUCTION RequestType = "/openrtb2/auction"
VIDEO RequestType = "/openrtb2/video"
SETUID RequestType = "/set_uid"
AMP RequestType = "/openrtb2/amp"
COOKIE_SYNC RequestType = "/cookie_sync"
AUCTION RequestType = "/openrtb2/auction"
VIDEO RequestType = "/openrtb2/video"
SETUID RequestType = "/set_uid"
AMP RequestType = "/openrtb2/amp"
NOTIFICATION_EVENT RequestType = "/event"
)

//Module that can perform transactional logging
Expand Down Expand Up @@ -72,6 +73,18 @@ func (f *FileLogger) LogAmpObject(ao *analytics.AmpObject) {
f.Logger.Flush()
}

//Logs NotificationEvent to file
func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent) {
danielguedesb marked this conversation as resolved.
Show resolved Hide resolved
if ne == nil {
return
}
//Code to parse the object and log in a way required
var b bytes.Buffer
b.WriteString(jsonifyNotificationEventObject(ne))
f.Logger.Debug(b.String())
f.Logger.Flush()
}

//Method to initialize the analytic module
func NewFileLogger(filename string) (analytics.PBSAnalyticsModule, error) {
options := glog.LogOptions{
Expand Down Expand Up @@ -176,3 +189,20 @@ func jsonifyAmpObject(ao *analytics.AmpObject) string {
return fmt.Sprintf("Transactional Logs Error: Amp object badly formed %v", err)
}
}

func jsonifyNotificationEventObject(ne *analytics.NotificationEvent) string {
danielguedesb marked this conversation as resolved.
Show resolved Hide resolved
type alias analytics.NotificationEvent
b, err := json.Marshal(&struct {
Type RequestType `json:"type"`
*alias
}{
Type: NOTIFICATION_EVENT,
alias: (*alias)(ne),
})

if err == nil {
return string(b)
} else {
return fmt.Sprintf("Transactional Logs Error: NotificationEvent object badly formed %v", err)
}
}
3 changes: 3 additions & 0 deletions analytics/pubstack/pubstack_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ func (p *PubstackModule) LogAuctionObject(ao *analytics.AuctionObject) {
p.eventChannels[auction].Push(payload)
}

func (p *PubstackModule) LogNotificationEventObject(ne *analytics.NotificationEvent) {
}

func (p *PubstackModule) LogVideoObject(vo *analytics.VideoObject) {
p.muxConfig.RLock()
defer p.muxConfig.RUnlock()
Expand Down
8 changes: 5 additions & 3 deletions config/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package config

// Account represents a publisher account configuration
type Account struct {
ID string `mapstructure:"id" json:"id"`
Disabled bool `mapstructure:"disabled" json:"disabled"`
CacheTTL DefaultTTLs `mapstructure:"cache_ttl" json:"cache_ttl"`
ID string `mapstructure:"id" json:"id"`
Disabled bool `mapstructure:"disabled" json:"disabled"`
CacheTTL DefaultTTLs `mapstructure:"cache_ttl" json:"cache_ttl"`
PriceGranularity string `mapstructure:"price_granularity" json:"price_granularity"`
danielguedesb marked this conversation as resolved.
Show resolved Hide resolved
EventsEnabled bool `mapstructure:"events_enabled" json:"events_enabled"`
}
11 changes: 11 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Configuration struct {
StoredRequests StoredRequests `mapstructure:"stored_requests"`
StoredRequestsAMP StoredRequests `mapstructure:"stored_amp_req"`
CategoryMapping StoredRequests `mapstructure:"category_mapping"`
VTrack VTrack `mapstructure:"vtrack"`
Accounts StoredRequests `mapstructure:"accounts"`
// Note that StoredVideo refers to stored video requests, and has nothing to do with caching video creatives.
StoredVideo StoredRequests `mapstructure:"stored_video_req"`
Expand Down Expand Up @@ -314,6 +315,12 @@ type PubstackBuffer struct {
Timeout string `mapstructure:"timeout"`
}

type VTrack struct {
SyntaxNode marked this conversation as resolved.
Show resolved Hide resolved
TimeoutMS int64 `mapstructure:"timeout_ms"`
AllowUnknownBidder bool `mapstructure:"allow_unknown_bidder"`
Enabled bool `mapstructure:"enabled"`
}

type HostCookie struct {
Domain string `mapstructure:"domain"`
Family string `mapstructure:"family"`
Expand Down Expand Up @@ -874,6 +881,10 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("stored_video_req.http_events.refresh_rate_seconds", 0)
v.SetDefault("stored_video_req.http_events.timeout_ms", 0)

v.SetDefault("vtrack.timeout_ms", 2000)
v.SetDefault("vtrack.allow_unknown_bidder", true)
v.SetDefault("vtrack.enabled", true)

v.SetDefault("accounts.filesystem.enabled", false)
v.SetDefault("accounts.filesystem.directorypath", "./stored_requests/data/by_id")
v.SetDefault("accounts.in_memory_cache.type", "none")
Expand Down
41 changes: 41 additions & 0 deletions endpoints/events/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package events

import (
"context"
"encoding/json"
jsonpatch "github.com/evanphx/json-patch"
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/stored_requests"
)

/**
* Retrieves an account and merges it with AccountDefaults
*/
func GetAccount(ctx context.Context, cfg *config.Configuration, fetcher stored_requests.AccountFetcher, id string) (*config.Account, []error) {
danielguedesb marked this conversation as resolved.
Show resolved Hide resolved
// account defaults is our baseline
account := cfg.AccountDefaults
account.ID = id

// attempt to retrieve account details using an AccountFetcher
if accountJSON, errs := fetcher.FetchAccount(ctx, id); len(errs) > 0 {
// tolerate account not found/empty and use account defaults
// if that's not the case return the errors that should be handler by the callers
if !accountNotFound(errs) {
return nil, errs
}
} else {
// merge with account defaults
// id resolved to a valid account, merge with AccountDefaults for a complete config
completeJSON, err := jsonpatch.MergePatch(cfg.AccountDefaultsJSON(), accountJSON)
if err == nil {
err = json.Unmarshal(completeJSON, &account)
}
if err != nil {
errs = append(errs, err)
return nil, errs
}
account.ID = id
}

return &account, nil
}
149 changes: 149 additions & 0 deletions endpoints/events/accounts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package events

import (
"context"
"encoding/json"
"fmt"
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/stored_requests"
"github.com/stretchr/testify/assert"
"testing"
)

// Mock AccountsFetcher
type mockAccountsFetcher struct {
Fail bool
Error error
EventsEnabled bool
T *testing.T
}

func (e *mockAccountsFetcher) FetchAccount(ctx context.Context, accountID string) (json.RawMessage, []error) {
if e.Fail {
return nil, []error{e.Error}
}

var acc = &config.Account{
ID: accountID,
EventsEnabled: false,
}

if e.EventsEnabled {
acc.EventsEnabled = true
}

s, err := json.Marshal(acc)
if err != nil {
e.T.Fatal(err)
}

return s, []error{}
}

func TestShouldReturnDefaultAccountWithSpecifiedIdWhenAccountNotFound(t *testing.T) {
// prepare
danielguedesb marked this conversation as resolved.
Show resolved Hide resolved
ctx := context.Background()

cfg := &config.Configuration{
AccountDefaults: config.Account{
EventsEnabled: true,
},
}
cfg.MarshalAccountDefaults()

af := mockAccountsFetcher{
Fail: true,
Error: stored_requests.NotFoundError{},
T: t,
}

acc, errs := GetAccount(ctx, cfg, &af, "test")

assert.Equal(t, 0, len(errs), "Expected 0 errors when account not found")
assert.EqualValues(t, config.Account{
EventsEnabled: true,
ID: "test",
}, *acc)

}

func TestShouldReturnNilAccountWhenFetcherFailsAttemptingToGetAccount(t *testing.T) {
// prepare
ctx := context.Background()

cfg := &config.Configuration{
AccountDefaults: config.Account{
EventsEnabled: true,
},
}
cfg.MarshalAccountDefaults()

af := mockAccountsFetcher{
Fail: true,
Error: fmt.Errorf("test error"),
T: t,
}

acc, errs := GetAccount(ctx, cfg, &af, "test")

assert.Equal(t, 1, len(errs), "Expected 1 errors")
assert.Nil(t, acc)
assert.Equal(t, "test error", errs[0].Error())

}

func TestShouldReturnAccountMergedWithAccountsDefaults(t *testing.T) {
// prepare
ctx := context.Background()

cfg := &config.Configuration{
AccountDefaults: config.Account{
EventsEnabled: false,
},
}
cfg.MarshalAccountDefaults()

af := mockAccountsFetcher{
Fail: false,
EventsEnabled: true,
T: t,
}

expectedAccount := config.Account{
EventsEnabled: true,
ID: "test",
}

acc, errs := GetAccount(ctx, cfg, &af, "test")

assert.Equal(t, 0, len(errs), "Expected 0 errors")
assert.EqualValues(t, expectedAccount, *acc)

}

func TestShouldReturnAccountMergedWithEmptyAccountsDefaults(t *testing.T) {
// prepare
ctx := context.Background()

cfg := &config.Configuration{
AccountDefaults: config.Account{},
}
cfg.MarshalAccountDefaults()

af := mockAccountsFetcher{
Fail: false,
EventsEnabled: true,
T: t,
}

expectedAccount := config.Account{
EventsEnabled: true,
ID: "test",
}

acc, errs := GetAccount(ctx, cfg, &af, "test")

assert.Equal(t, 0, len(errs), "Expected 0 errors")
assert.EqualValues(t, expectedAccount, *acc)

}
Loading