Skip to content

Commit

Permalink
Media.net Analytics improvements
Browse files Browse the repository at this point in the history
Co-authored-by: monis.q <monis.q@media.net>
  • Loading branch information
monis0395 and monisq committed Jul 23, 2020
1 parent e4ff582 commit 7535132
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 15 deletions.
79 changes: 66 additions & 13 deletions modules/medianetAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import CONSTANTS from '../src/constants.json';
import * as utils from '../src/utils.js';
import { ajax } from '../src/ajax.js';
import { getRefererInfo } from '../src/refererDetection.js';
import { getPriceGranularity, AUCTION_IN_PROGRESS, AUCTION_COMPLETED } from '../src/auction.js'
import { AUCTION_COMPLETED, AUCTION_IN_PROGRESS, getPriceGranularity } from '../src/auction.js'

const analyticsType = 'endpoint';
const ENDPOINT = 'https://pb-logs.media.net/log?logid=kfk&evtid=prebid_analytics_events_client';
Expand All @@ -29,6 +29,7 @@ const ERROR_CONFIG_FETCH = 'analytics_config_ajax_fail';
const BID_SUCCESS = 1;
const BID_NOBID = 2;
const BID_TIMEOUT = 3;
const BID_FLOOR_REJECTED = 12;
const DUMMY_BIDDER = '-2';

const CONFIG_PENDING = 0;
Expand Down Expand Up @@ -151,7 +152,7 @@ class PageDetail {
this.canonical_url = canonicalUrl;
this.og_url = ogUrl;
this.twitter_url = twitterUrl;
this.screen = this._getWindowSize()
this.screen = this._getWindowSize();
}

_getTopWindowReferrer() {
Expand Down Expand Up @@ -201,9 +202,9 @@ class PageDetail {
}

class AdSlot {
constructor(mediaTypes, bannerSizes, tmax, supplyAdCode, adext) {
constructor(mediaTypes, allMediaTypeSizes, tmax, supplyAdCode, adext, context, adSize) {
this.mediaTypes = mediaTypes;
this.bannerSizes = bannerSizes;
this.allMediaTypeSizes = allMediaTypeSizes;
this.tmax = tmax;
this.supplyAdCode = supplyAdCode;
this.adext = adext;
Expand All @@ -213,6 +214,8 @@ class AdSlot {
// shouldBeLogged is assigned when requested,
// since we are waiting for logging percent response
this.shouldBeLogged = undefined;
this.context = context;
this.adSize = adSize; // old ad unit sizes
}

getShouldBeLogged() {
Expand All @@ -226,10 +229,12 @@ class AdSlot {
return Object.assign({
supcrid: this.supplyAdCode,
mediaTypes: this.mediaTypes && this.mediaTypes.join('|'),
szs: this.bannerSizes.join('|'),
szs: this.allMediaTypeSizes.map(sz => sz.join('x')).join('|'),
tmax: this.tmax,
targ: JSON.stringify(this.targeting),
ismn: this.medianetPresent
ismn: this.medianetPresent,
vplcmtt: this.context,
sz2: this.adSize.map(sz => sz.join('x')).join('|'),
},
this.adext && {'adext': JSON.stringify(this.adext)},
);
Expand Down Expand Up @@ -261,6 +266,8 @@ class Bid {
this.crid = undefined;
this.pubcrid = undefined;
this.mpvid = undefined;
this.floorPrice = undefined;
this.floorRule = undefined;
}

get size() {
Expand Down Expand Up @@ -290,6 +297,8 @@ class Bid {
crid: this.crid,
pubcrid: this.pubcrid,
mpvid: this.mpvid,
bidflr: this.floorPrice,
flrrule: this.floorRule,
ext: JSON.stringify(this.ext)
}
}
Expand All @@ -306,6 +315,7 @@ class Auction {
this.setTargetingTime = undefined;
this.auctionEndTime = undefined;
this.bidWonTime = undefined;
this.floorData = {};
}

hasEnded() {
Expand All @@ -319,13 +329,22 @@ class Auction {
tts: this.setTargetingTime - this.auctionInitTime,
wts: this.bidWonTime - this.auctionInitTime,
aucstatus: this.status,
acid: this.acid
acid: this.acid,
flrdata: this._mergeFieldsToLog({
ln: this.floorData.location,
skp: this.floorData.skipped,
enfj: utils.deepAccess(this.floorData, 'enforcements.enforceJS'),
enfd: utils.deepAccess(this.floorData, 'enforcements.floorDeals'),
sr: this.floorData.skipRate,
fs: this.floorData.fetchStatus
}),
flrver: this.floorData.modelVersion
}
}

addSlot(supplyAdCode, { mediaTypes, bannerSizes, tmax, adext }) {
addSlot(supplyAdCode, { mediaTypes, allMediaTypeSizes, tmax, adext, context, adSize }) {
if (supplyAdCode && this.adSlots[supplyAdCode] === undefined) {
this.adSlots[supplyAdCode] = new AdSlot(mediaTypes, bannerSizes, tmax, supplyAdCode, adext);
this.adSlots[supplyAdCode] = new AdSlot(mediaTypes, allMediaTypeSizes, tmax, supplyAdCode, adext, context, adSize);
this.addBid(
new Bid('-1', DUMMY_BIDDER, 'client', '-1', supplyAdCode)
);
Expand All @@ -351,13 +370,27 @@ class Auction {
getWinnerAdslotBid(adslot) {
return this.getAdslotBids(adslot).filter((bid) => bid.winner);
}

_mergeFieldsToLog(objParams) {
let logParams = [];
let value;
for (const param of Object.keys(objParams)) {
value = objParams[param];
logParams.push(param + '=' + (value === undefined ? '' : value));
}
return logParams.join('||');
}
}

function auctionInitHandler({auctionId, timestamp}) {
function auctionInitHandler({auctionId, timestamp, bidderRequests}) {
if (auctionId && auctions[auctionId] === undefined) {
auctions[auctionId] = new Auction(auctionId);
auctions[auctionId].auctionInitTime = timestamp;
}
const floorData = utils.deepAccess(bidderRequests, '0.bids.0.floorData');
if (floorData) {
auctions[auctionId].floorData = {...floorData};
}
}

function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, uspConsent, gdpr }) {
Expand All @@ -375,13 +408,16 @@ function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, us
const { adUnitCode, bidder, mediaTypes, sizes, bidId, src } = bid;
if (!auctions[auctionId].adSlots[adUnitCode]) {
auctions[auctionId].auctionStartTime = auctionStart;
const sizeObject = _getSizes(mediaTypes, sizes);
auctions[auctionId].addSlot(
adUnitCode,
Object.assign({},
(mediaTypes instanceof Object) && { mediaTypes: Object.keys(mediaTypes) },
{ bannerSizes: utils.deepAccess(mediaTypes, 'banner.sizes') || sizes || [] },
{ allMediaTypeSizes: [].concat(sizeObject.banner, sizeObject.native, sizeObject.video) },
{ adext: utils.deepAccess(mediaTypes, 'banner.ext') || '' },
{ tmax: timeout }
{ tmax: timeout },
{ context: utils.deepAccess(mediaTypes, 'video.context') || '' },
{ adSize: sizeObject.banner }
)
);
}
Expand All @@ -395,6 +431,17 @@ function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, us
});
}

function _getSizes(mediaTypes, sizes) {
const banner = utils.deepAccess(mediaTypes, 'banner.sizes') || sizes || [];
const native = utils.deepAccess(mediaTypes, 'native') ? [[1, 1]] : [];
const playerSize = utils.deepAccess(mediaTypes, 'video.playerSize') || [];
let video = [];
if (playerSize.length === 2) {
video = [playerSize]
}
return { banner, native, video }
}

function bidResponseHandler(bid) {
const { width, height, mediaType, cpm, requestId, timeToRespond, auctionId, dealId } = bid;
const {originalCpm, bidderCode, creativeId, adId, currency} = bid;
Expand All @@ -411,6 +458,8 @@ function bidResponseHandler(bid) {
{ cpm, width, height, mediaType, timeToRespond, dealId, creativeId },
{ adId, currency }
);
bidObj.floorPrice = utils.deepAccess(bid, 'floorData.floorValue');
bidObj.floorRule = utils.deepAccess(bid, 'floorData.floorRule');
bidObj.originalCpm = originalCpm || cpm;
let dfpbd = utils.deepAccess(bid, 'adserverTargeting.hb_pb');
if (!dfpbd) {
Expand All @@ -419,7 +468,11 @@ function bidResponseHandler(bid) {
dfpbd = bid[priceGranularityKey] || cpm;
}
bidObj.dfpbd = dfpbd;
bidObj.status = BID_SUCCESS;
if (bid.status === CONSTANTS.BID_STATUS.BID_REJECTED) {
bidObj.status = BID_FLOOR_REJECTED;
} else {
bidObj.status = BID_SUCCESS;
}

if (bidderCode === MEDIANET_BIDDER_CODE && bid.ext instanceof Object) {
Object.assign(
Expand Down
51 changes: 49 additions & 2 deletions test/spec/modules/medianetAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,26 @@ const {

const MOCK = {
AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739},
AUCTION_INIT_WITH_FLOOR: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'bidderRequests': [{'bids': [{ 'floorData': {'enforcements': {'enforceJS': true}} }]}]},
BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743},
BID_RESPONSE: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]},
MULTI_FORMAT_BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'video': {'playerSize': [640, 480], 'context': 'instream'}, 'native': {'image': {'required': true, 'sizes': [150, 50]}, 'title': {'required': true, 'len': 80}}, 'ext': ['asdads']}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743},
BID_RESPONSE: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]},
AUCTION_END: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'auctionEnd': 1584563605739},
SET_TARGETING: {'div-gpt-ad-1460505748561-0': {'prebid_test': '1', 'hb_format': 'banner', 'hb_source': 'client', 'hb_size': '300x250', 'hb_pb': '2.00', 'hb_adid': '3e6e4bce5c8fb3', 'hb_bidder': 'medianet', 'hb_format_medianet': 'banner', 'hb_source_medianet': 'client', 'hb_size_medianet': '300x250', 'hb_pb_medianet': '2.00', 'hb_adid_medianet': '3e6e4bce5c8fb3', 'hb_bidder_medianet': 'medianet'}},
BID_WON: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]},
NO_BID: {'bidder': 'medianet', 'params': {'cid': 'test123', 'crid': '451466393', 'site': {}}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '303fa0c6-682f-4aea-8e4a-dc68f0d5c7d5', 'sizes': [[300, 250], [300, 600]], 'bidId': '28248b0e6aece2', 'bidderRequestId': '13fccf3809fe43', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'},
BID_TIMEOUT: [{'bidId': '28248b0e6aece2', 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'params': [{'cid': 'test123', 'crid': '451466393', 'site': {}}, {'cid': '8CUX0H51P', 'crid': '451466393', 'site': {}}], 'timeout': 6}]
}

function performAuctionWithFloorConfig() {
events.emit(AUCTION_INIT, MOCK.AUCTION_INIT_WITH_FLOOR);
events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
events.emit(AUCTION_END, MOCK.AUCTION_END);
events.emit(SET_TARGETING, MOCK.SET_TARGETING);
events.emit(BID_WON, MOCK.BID_WON);
}

function performStandardAuctionWithWinner() {
events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
Expand All @@ -28,6 +39,14 @@ function performStandardAuctionWithWinner() {
events.emit(BID_WON, MOCK.BID_WON);
}

function performMultiFormatAuctionWithNoBid() {
events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
events.emit(BID_REQUESTED, MOCK.MULTI_FORMAT_BID_REQUESTED);
events.emit(BID_RESPONSE, MOCK.BID_RESPONSE);
events.emit(AUCTION_END, MOCK.AUCTION_END);
events.emit(SET_TARGETING, MOCK.SET_TARGETING);
}

function performStandardAuctionWithNoBid() {
events.emit(AUCTION_INIT, MOCK.AUCTION_INIT);
events.emit(BID_REQUESTED, MOCK.BID_REQUESTED);
Expand Down Expand Up @@ -115,6 +134,17 @@ describe('Media.net Analytics Adapter', function() {
expect(medianetAnalytics.getlogsQueue().length).to.equal(0);
});

it('should have all applicable sizes in request', function() {
medianetAnalytics.clearlogsQueue();
performMultiFormatAuctionWithNoBid();
const noBidLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log))[0];
medianetAnalytics.clearlogsQueue();

expect(noBidLog.szs).to.equal(encodeURIComponent('300x250|1x1|640x480'));
expect(noBidLog.vplcmtt).to.equal('instream');
expect(noBidLog.sz2).to.equal(encodeURIComponent('300x250'));
});

it('should have winner log in standard auction', function() {
medianetAnalytics.clearlogsQueue();
performStandardAuctionWithWinner();
Expand Down Expand Up @@ -142,7 +172,24 @@ describe('Media.net Analytics Adapter', function() {
ogbdp: '1.1495',
flt: '1',
supcrid: 'div-gpt-ad-1460505748561-0',
mpvid: '123'
mpvid: '123',
bidflr: '1.1'
});
});

it('should have correct bid floor data in winner log', function() {
medianetAnalytics.clearlogsQueue();
performAuctionWithFloorConfig();
let winnerLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log)).filter((log) => log.winner);
medianetAnalytics.clearlogsQueue();

expect(winnerLog[0]).to.include({
winner: '1',
curr: 'USD',
ogbdp: '1.1495',
bidflr: '1.1',
flrrule: 'banner',
flrdata: encodeURIComponent('ln=||skp=||enfj=true||enfd=||sr=||fs=')
});
});

Expand Down

0 comments on commit 7535132

Please sign in to comment.