Skip to content

Commit

Permalink
GreenbidsAnalyticsReporter: Add CPM, bidder params, UserAgent, PBS fl…
Browse files Browse the repository at this point in the history
…ag (#3282)
  • Loading branch information
EvgeniiMunin authored Jul 16, 2024
1 parent 76f856f commit 7bc8db9
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.Banner;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Device;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.request.Native;
import com.iab.openrtb.request.Site;
Expand All @@ -23,7 +24,7 @@
import org.prebid.server.analytics.reporter.greenbids.model.ExtBanner;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsAdUnit;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsAnalyticsProperties;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsBids;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsBid;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsPrebidExt;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsSource;
import org.prebid.server.analytics.reporter.greenbids.model.GreenbidsUnifiedCode;
Expand Down Expand Up @@ -61,6 +62,8 @@ public class GreenbidsAnalyticsReporter implements AnalyticsReporter {

private static final String BID_REQUEST_ANALYTICS_EXTENSION_NAME = "greenbids";
private static final int RANGE_16_BIT_INTEGER_DIVISION_BASIS = 0x10000;
private static final String ANALYTICS_REQUEST_ORIGIN_HEADER = "X-Request-Origin";
private static final String PREBID_SERVER_HEADER_VALUE = "Prebid Server";
private static final Logger logger = LoggerFactory.getLogger(GreenbidsAnalyticsReporter.class);

private final GreenbidsAnalyticsProperties greenbidsAnalyticsProperties;
Expand Down Expand Up @@ -103,6 +106,10 @@ public <T> Future<Void> processEvent(T event) {

final GreenbidsPrebidExt greenbidsBidRequestExt = parseBidRequestExt(auctionContext.getBidRequest());

if (greenbidsBidRequestExt == null) {
return Future.succeededFuture();
}

final String greenbidsId = UUID.randomUUID().toString();
final String billingId = UUID.randomUUID().toString();

Expand All @@ -127,7 +134,13 @@ public <T> Future<Void> processEvent(T event) {

final MultiMap headers = MultiMap.caseInsensitiveMultiMap()
.add(HttpUtil.ACCEPT_HEADER, HttpHeaderValues.APPLICATION_JSON)
.add(HttpUtil.CONTENT_TYPE_HEADER, HttpHeaderValues.APPLICATION_JSON);
.add(HttpUtil.CONTENT_TYPE_HEADER, HttpHeaderValues.APPLICATION_JSON)
.add(ANALYTICS_REQUEST_ORIGIN_HEADER, PREBID_SERVER_HEADER_VALUE);

Optional.ofNullable(auctionContext.getBidRequest())
.map(BidRequest::getDevice)
.map(Device::getUa)
.ifPresent(userAgent -> headers.add(HttpUtil.USER_AGENT_HEADER, userAgent));

final Future<HttpClientResponse> responseFuture = httpClient.post(
greenbidsAnalyticsProperties.getAnalyticsServerUrl(),
Expand All @@ -146,7 +159,7 @@ private GreenbidsPrebidExt parseBidRequestExt(BidRequest bidRequest) {
.filter(this::isNotEmptyObjectNode)
.map(analytics -> (ObjectNode) analytics.get(BID_REQUEST_ANALYTICS_EXTENSION_NAME))
.map(this::toGreenbidsPrebidExt)
.orElse(GreenbidsPrebidExt.of(null, null));
.orElse(null);
}

private GreenbidsPrebidExt toGreenbidsPrebidExt(ObjectNode adapterNode) {
Expand All @@ -169,10 +182,16 @@ private Future<Void> processAnalyticServerResponse(HttpClientResponse response)
return Future.failedFuture(new PreBidException("Unexpected response status: " + response.getStatusCode()));
}

private boolean isSampled(double samplingRate, String greenbidsId) {
private boolean isSampled(Double samplingRate, String greenbidsId) {
if (samplingRate == null) {
logger.warn("Warning: Sampling rate is not defined in request. Set sampling at "
+ greenbidsAnalyticsProperties.getDefaultSamplingRate());
return true;
}

if (samplingRate < 0 || samplingRate > 1) {
logger.warn("Warning: Sampling rate must be between 0 and 1");
return false;
return true;
}

final double exploratorySamplingRate = samplingRate
Expand Down Expand Up @@ -213,7 +232,7 @@ private CommonMessage createBidMessage(
final Map<String, NonBid> seatsWithNonBids = getSeatsWithNonBids(auctionContext);

final List<GreenbidsAdUnit> adUnitsWithBidResponses = imps.stream().map(imp -> createAdUnit(
imp, seatsWithBids, seatsWithNonBids)).toList();
imp, seatsWithBids, seatsWithNonBids, bidResponse.getCur())).toList();

final String auctionId = bidRequest
.map(BidRequest::getId)
Expand All @@ -224,11 +243,14 @@ private CommonMessage createBidMessage(
.map(Site::getPage)
.orElse(null);

final Double greenbidsSamplingRate = Optional.ofNullable(greenbidsImpExt.getGreenbidsSampling())
.orElse(greenbidsAnalyticsProperties.getDefaultSamplingRate());

return CommonMessage.builder()
.version(greenbidsAnalyticsProperties.getAnalyticsServerVersion())
.auctionId(auctionId)
.referrer(referrer)
.sampling(greenbidsImpExt.getGreenbidsSampling())
.sampling(greenbidsSamplingRate)
.prebidServer(prebidVersionProvider.getNameVersionRecord())
.greenbidsId(greenbidsId)
.pbuid(greenbidsImpExt.getPbuid())
Expand Down Expand Up @@ -271,23 +293,30 @@ private static SeatNonBid toSeatNonBid(String bidder, BidRejectionTracker bidRej
private GreenbidsAdUnit createAdUnit(
Imp imp,
Map<String, Bid> seatsWithBids,
Map<String, NonBid> seatsWithNonBids) {
Map<String, NonBid> seatsWithNonBids,
String currency) {
final ExtBanner extBanner = getExtBanner(imp.getBanner());
final Video video = imp.getVideo();
final Native nativeObject = imp.getXNative();

final MediaTypes mediaTypes = MediaTypes.of(extBanner, video, nativeObject);

final List<GreenbidsBids> bids = extractBidders(imp, seatsWithBids, seatsWithNonBids);

final ObjectNode impExt = imp.getExt();
final String adUnitCode = imp.getId();

final ExtImpPrebid impExtPrebid = Optional.ofNullable(impExt)
.map(ext -> ext.get("prebid"))
.map(this::extImpPrebid)
.orElseThrow(() -> new PreBidException("imp.ext.prebid should not be empty"));

final GreenbidsUnifiedCode greenbidsUnifiedCode = getGpid(impExt)
.or(() -> getStoredRequestId(impExt))
.or(() -> getStoredRequestId(impExtPrebid))
.orElseGet(() -> GreenbidsUnifiedCode.of(
adUnitCode, GreenbidsSource.AD_UNIT_CODE_SOURCE.getValue()));

final List<GreenbidsBid> bids = extractBidders(
imp.getId(), seatsWithBids, seatsWithNonBids, impExtPrebid, currency);

return GreenbidsAdUnit.builder()
.code(adUnitCode)
.unifiedCode(greenbidsUnifiedCode)
Expand Down Expand Up @@ -317,16 +346,24 @@ private static ExtBanner getExtBanner(Banner banner) {
.build();
}

private List<GreenbidsBids> extractBidders(
Imp imp, Map<String, Bid> seatsWithBids, Map<String, NonBid> seatsWithNonBids) {
private List<GreenbidsBid> extractBidders(
String impId,
Map<String, Bid> seatsWithBids,
Map<String, NonBid> seatsWithNonBids,
ExtImpPrebid impExtPrebid,
String currency) {
final ObjectNode bidders = impExtPrebid.getBidder();

return Stream.concat(
seatsWithBids.entrySet().stream()
.filter(entry -> entry.getValue().getImpid().equals(imp.getId()))
.map(entry -> GreenbidsBids.ofBid(entry.getKey(), entry.getValue())),
.filter(entry -> entry.getValue().getImpid().equals(impId))
.map(entry -> GreenbidsBid.ofBid(
entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency)),
seatsWithNonBids.entrySet().stream()
.filter(entry -> entry.getValue().getImpId().equals(imp.getId()))
.map(entry -> GreenbidsBids.ofNonBid(entry.getKey(), entry.getValue())))
.collect(Collectors.toList());
.filter(entry -> entry.getValue().getImpId().equals(impId))
.map(entry -> GreenbidsBid.ofNonBid(
entry.getKey(), entry.getValue(), bidders.get(entry.getKey()), currency)))
.toList();
}

private static Optional<GreenbidsUnifiedCode> getGpid(ObjectNode impExt) {
Expand All @@ -337,11 +374,8 @@ private static Optional<GreenbidsUnifiedCode> getGpid(ObjectNode impExt) {
GreenbidsUnifiedCode.of(gpid, GreenbidsSource.GPID_SOURCE.getValue()));
}

private Optional<GreenbidsUnifiedCode> getStoredRequestId(ObjectNode impExt) {
return Optional.ofNullable(impExt)
.map(ext -> ext.get("prebid"))
.map(this::extImpPrebid)
.map(ExtImpPrebid::getStoredrequest)
private Optional<GreenbidsUnifiedCode> getStoredRequestId(ExtImpPrebid extImpPrebid) {
return Optional.ofNullable(extImpPrebid.getStoredrequest())
.map(ExtStoredRequest::getId)
.map(storedRequestId ->
GreenbidsUnifiedCode.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class CommonMessage {

String referrer;

double sampling;
Double sampling;

@JsonProperty("prebidServer")
String prebidServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ public class GreenbidsAdUnit {
@JsonProperty("mediaTypes")
MediaTypes mediaTypes;

List<GreenbidsBids> bids;
List<GreenbidsBid> bids;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public class GreenbidsAnalyticsProperties {

Double exploratorySamplingSplit;

Double defaultSamplingRate;

String analyticsServerVersion;

String analyticsServerUrl;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package org.prebid.server.analytics.reporter.greenbids.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.iab.openrtb.response.Bid;
import lombok.Builder;
import lombok.Value;
import org.prebid.server.auction.model.BidRejectionReason;
import org.prebid.server.proto.openrtb.ext.response.seatnonbid.NonBid;

import java.math.BigDecimal;

@Builder(toBuilder = true)
@Value
public class GreenbidsBids {
public class GreenbidsBid {

String bidder;

Expand All @@ -19,19 +22,30 @@ public class GreenbidsBids {
@JsonProperty("hasBid")
Boolean hasBid;

public static GreenbidsBids ofBid(String seat, Bid bid) {
return GreenbidsBids.builder()
JsonNode params;

BigDecimal cpm;

String currency;

public static GreenbidsBid ofBid(String seat, Bid bid, JsonNode params, String currency) {
return GreenbidsBid.builder()
.bidder(seat)
.isTimeout(false)
.hasBid(bid != null)
.params(params)
.cpm(bid.getPrice())
.currency(currency)
.build();
}

public static GreenbidsBids ofNonBid(String seat, NonBid nonBid) {
return GreenbidsBids.builder()
public static GreenbidsBid ofNonBid(String seat, NonBid nonBid, JsonNode params, String currency) {
return GreenbidsBid.builder()
.bidder(seat)
.isTimeout(nonBid.getStatusCode() == BidRejectionReason.TIMED_OUT)
.hasBid(false)
.params(params)
.currency(currency)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,14 @@ private static class GreenbidsAnalyticsConfigurationProperties {

Double exploratorySamplingSplit;

Double defaultSamplingRate;

Long timeoutMs;

public GreenbidsAnalyticsProperties toComponentProperties() {
return GreenbidsAnalyticsProperties.builder()
.exploratorySamplingSplit(getExploratorySamplingSplit())
.defaultSamplingRate(getDefaultSamplingRate())
.analyticsServerVersion(getAnalyticsServerVersion())
.analyticsServerUrl(getAnalyticsServer())
.timeoutMs(getTimeoutMs())
Expand Down
Loading

0 comments on commit 7bc8db9

Please sign in to comment.