Impression handler

CloudBees Feature Flags SDK allows you to configure a function to be called when a flag is being evaluated. This function can be used to report the flag state to your analytics and application performance management system (e.g. new relic).

On Rox.setup method, you can provide an impressionHandler which is called when the code checks the flag value. The function is called with two arguments on the client side, and if the context was supplied to the flag evaluation, it will also be sent as a third argument to the function.

  • reporting - an object describing the flag name and value

  • experiment - an object describing the experiment that this flag belongs to

  • context - the context that was passed to the flag evaluation function

The following code examples show how to add the impressionHandler in various SDKs:

Swift Objective-C Android React Native JavaScript Node.js JavaScript SSR JVM .NET Python Go Ruby PHP C C++
let options = RoxOptions()
options.impressionHandler = {reporting, experiment in
  if (experiment != nil){
    print("flag \(reporting.name!) value is \(reporting.value!), it is part of '\(experiment!.name!)' experiment")
    print("experiment labels:\((experiment?.labels ?? Set<String>()).joined(separator: ","))")
  } else {
    print("no experiment configured for flag \(reporting.name!). default value \(reporting.value!) was used")
  }
}
ROX.setup(withKey:environmentKey, options: options  )
ROXOptions* options = [[ROXOptions alloc] init];
options.impressionHandler =^(ROXReportingValue * _Nonnull reporting, ROXExperiment * _Nullable experiment) {
  if (experiment){
    NSLog(@"flag %@ value is %@, it is part of '%@' experiment",reporting.name, reporting.value, experiment.name);
    NSLog(@"experiment labels: %@", [[experiment.labels allObjects] componentsJoinedByString:@","]);
  } else {
    NSLog(@"no experiment configured for flag %@. default value %@ was used", reporting.name, reporting.value);
  }
};
[ROX setupWithKey:environmentKey options:options]
RoxOptions options = new RoxOptions.Builder()
  .withImpressionHandler(new ImpressionHandler() {
    @Override
    public void onImpression(ReportingValue reporting, Experiment experiment) {
      if (experiment != null){
        Log.i(TAG,"flag " + reporting.getName() + " value is " + reporting.getValue() + ", it is part of " + experiment.getName() +" experiment which has the following labels:" + String.Join(",", experiment.getLabels));
      } else {
        Log.i(TAG,"No experiment configured for flag " + reporting.getName() + ". default value " + reporting.getValue() + " was used");
      }
    }
  })
  .build();

Rox.setup(context, options);
Rox.setup(environmentKey, {
  impressionHandler: (reporting, experiment) => {
    if (experiment){
      console.log('flag ' + reporting.name + ' value is ' + reporting.value + ', it is part of ' + experiment.name +' experiment which has the following labels:' + experiment.labels.join(','));
    } else {
      console.log('No experiment configured for flag ' + reporting.name + '. default value ' + reporting.value + ' was used');
    }
  }
})
Rox.setup(environmentKey, {
  impressionHandler: (reporting, experiment) => {
    if (experiment){
      console.log('flag ' + reporting.name + ' value is ' + reporting.value + ', it is part of ' + experiment.name +' experiment');
    } else {
      console.log('No experiment configured for flag ' + reporting.name + '. default value ' + reporting.value + ' was used');
    }
  }
});
await Rox.setup(environmentKey, {
  impressionHandler: (reporting, experiment, context) => {
    if (experiment){
      console.log('flag ' + reporting.name + ' for context ' + context + ' value is ' + reporting.value + ', it is part of ' + experiment.name +' experiment which has the following labels:' + experiment.labels.join(','));
    } else {
      console.log('No experiment configured for flag ' + reporting.name + '. default value ' + reporting.value + ' was used');
    }
  }
})
import {Rox} from 'rox-ssr';

await Rox.setup(environmentKey, {
  impressionHandler: (reporting, experiment, context) => {
    if (experiment){
      console.log('flag ' + reporting.name + ' for context ' + context + ' value is ' + reporting.value + ', it is part of ' + experiment.name +' experiment which has the following labels:' + experiment.labels.join(','));
    } else {
      console.log('No experiment configured for flag ' + reporting.name + '. default value ' + reporting.value + ' was used');
    }
  }
});
RoxOptions options = new RoxOptions.Builder()
  .withImpressionHandler(new ImpressionHandler() {
    @Override
    public void onImpression(ReportingValue reporting, Experiment experiment) {
        if (experiment != null){
        System.out.println("flag " + reporting.getName() + " value is " + reporting.getValue() + ", it is part of " + experiment.getName() +" experiment which has the following labels:" + String.join(",", experiment.getLabels()));
      } else {
        System.out.println("No experiment configured for flag " + reporting.getName() + ". default value " + reporting.getValue() + " was used");
      }
    }
  })
  .build();

Rox.setup(ROLLOUT_KEY, options).get();
var Options = new RoxOptions(new RoxOptions.RoxOptionsBuilder
{
    ImpressionHandler = (sender, e) =>
    {
        if (e.Experiment != null)
        {
            Console.WriteLine("flag " + e.ReportingValue.Name + " value is " + e.ReportingValue.Value + ", it is part of " + e.Experiment.Name +" experiment which has the following labels:" + string.Join(",", e.Experiment.Labels));
        }
        else
        {
            Console.WriteLine("No experiment configured for flag " + e.ReportingValue.Name + ". default value " + e.ReportingValue.Value + " was used");
        }
    }
}

await Rox.Setup(ROLLOUT_KEY, Options);
def on_impression(e):
    if e.experiment is not None :
        print('flag %s value is %s, it is part of "%s" experiment, that has those labels: %s' % (e.reporting_value.name, e.reporting_value.value, e.experiment.name, ','.join(e.experiment.labels)))
    else :
        print('no experiment configured for flag %s. default value %s was used' % (e.reporting_value.name, e.reporting_value.value))

options = RoxOptions(
  impression_handler=on_impression
)

Rox.setup(<ROLLOUT_KEY>, options).result()
options := server.NewRoxOptions(server.RoxOptionsBuilder {
    ImpressionHandler: func(e model.ImpressionArgs) {
        if e.Experiment != nil {
            fmt.Println("flag", e.ReportingValue.Name, "value is", e.ReportingValue.Value, ", it is part of", e.Experiment.Name, "experiment, which has the following labels:", strings.Join(e.Experiment.Labe    ls, ","))
        } else {
            fmt.Println("No experiment configured for flag ", e.ReportingValue.Name, ". default value ", e.ReportingValue.Value, " was used")
        }
    },
})

<-rox.Setup(ROLLOUT_KEY, options);
impression_handler = proc do

e

if !e.experiment.nil? puts "flag #{e.reporting_value.name} value is #{e.reporting_value.value}, it is part of #{e.experiment.name} experiment, that has those labels: #{e.experiment.labels.join(',')}" else puts "no experiment configured for flag #{e.reporting_value.name}. default value #{e.reporting_value.value} was used" end end

options = Rox::Server::RoxOptions.new( impression_handler: impression_handler )

Rox::Server::RoxServer.setup(<ROLLOUT_KEY>, option).join ----

use Rox\Server\Rox;
use Rox\Server\RoxOptions;
use Rox\Server\RoxOptionsBuilder;
use Rox\Core\Impression\ImpressionArgs;
use Rox\Core\Impression\ImpressionInvokerInterface;

$roxOptionsBuilder = (new RoxOptionsBuilder())
    ->setImpressionHandler(function (ImpressionInvokerInterface $sender, ImpressionArgs $args) {
        if ($args != null && $args->getExperiment() != null) {
            echo 'flag ' . $args->getReportingValue()->getName() . ' value is ' . $args->getReportingValue()->getValue();
            echo ' it is part of ' . $args->getExperiment()->getName() . ' experiment that has those labels: ' . implode(', ', $args->getExperiment()->getLabels());
        } else {
            echo 'no experiment configured for flag ' . $args->getReportingValue()->getName() . '. default value ' . $args->getReportingValue()->getValue() . ' was used';
        }
    })

Rox::setup(ROLLOUT_KEY, new RoxOptions($roxOptionsBuilder));