Skip to content

Commit 25a6c10

Browse files
authored
Canvas options (QC-253) (#434)
* Allow to add or update metadata in MO * CCDB json retrieval: also return the metadata * Let user set drawOptions and displayHints
1 parent 32923cd commit 25a6c10

8 files changed

Lines changed: 141 additions & 3 deletions

File tree

Framework/include/QualityControl/DatabaseInterface.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,18 +92,21 @@ class DatabaseInterface
9292
/**
9393
* \brief Look up a monitor object and return it in JSON format.
9494
* Look up a monitor object and return it in JSON format if found or an empty string if not.
95+
* The headers associated with the object are added to the JSON object under the key "metadata".
9596
* @deprecated
9697
*/
9798
virtual std::string retrieveMOJson(std::string taskName, std::string objectName, long timestamp = -1) = 0;
9899
/**
99100
* \brief Look up a quality object and return it in JSON format.
100101
* Look up a quality object and return it in JSON format if found or an empty string if not.
102+
* The headers associated with the object are added to the JSON object under the key "metadata".
101103
* @deprecated
102104
*/
103105
virtual std::string retrieveQOJson(std::string qoPath, long timestamp = -1) = 0;
104106
/**
105107
* \brief Look up an object and return it in JSON format.
106108
* Look up an object and return it in JSON format if found or an empty string if not.
109+
* The headers associated with the object are added to the JSON object under the key "metadata".
107110
* \param path the path of the object
108111
* \param timestamp the timestamp to query the object
109112
* \param metadata filters under the form of key-value pairs to select data
@@ -112,6 +115,7 @@ class DatabaseInterface
112115
/**
113116
* \brief Look up an object and return it in JSON format.
114117
* Look up an object and return it in JSON format if found or an empty string if not.
118+
* The headers associated with the object are added to the JSON object under the key "metadata".
115119
* A default timestamp of -1 is used, usually meaning to use the current timestamp.
116120
* \param path the path to the object
117121
*/

Framework/include/QualityControl/MonitorObject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class MonitorObject : public TObject
9595
void updateMetadata(std::string key, std::string value);
9696
/// \brief Get the full map of user's metadata
9797
const std::map<std::string, std::string>& getMetadataMap() const;
98+
/// \brief Update the value of metadata or add it if it does not exist yet.
99+
void addOrUpdateMetadata(std::string key, std::string value);
98100

99101
void Draw(Option_t* option) override;
100102
TObject* DrawClone(Option_t* option) const override;

Framework/include/QualityControl/ObjectsManager.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class ObjectsManager
4949
explicit ObjectsManager(TaskConfig& taskConfig, bool noDiscovery = false);
5050
virtual ~ObjectsManager();
5151

52+
static const std::string gDrawOptionsKey;
53+
static const std::string gDisplayHintsKey;
54+
5255
/**
5356
* Start publishing the object obj, i.e. it will be pushed forward in the workflow at regular intervals.
5457
* The ownership remains to the caller.
@@ -98,6 +101,38 @@ class ObjectsManager
98101
*/
99102
void addMetadata(const std::string& objectName, const std::string& key, const std::string& value);
100103

104+
/**
105+
* \brief Set default draw options for this object.
106+
* If possible, the object will be drawn with these options (in the ROOT sense).
107+
* See for example https://root.cern/doc/master/classTHistPainter.html#HP01
108+
* E.g. manager->setDefaultDRawOptions("histo1", "colz");
109+
* @param objectName Name of the object affected by these drawOptions.
110+
* @param options The list of options.
111+
* @throw ObjectNotFoundError if object is not found.
112+
*/
113+
void setDefaultDrawOptions(const std::string& objectName, const std::string& options);
114+
115+
/**
116+
* See setDefaultDrawOptions(const std::string& objectName, const std::string& hioptionsnts).
117+
*/
118+
void setDefaultDrawOptions(TObject* obj, const std::string& options);
119+
120+
/**
121+
* \brief Indicate how to display this object.
122+
* A number of options can be set on a canvas to influence the way the object is displayed.
123+
* For drawOptions, use setDefaultDrawOptions, for others such as logarithmic scale or grid, use this method.
124+
* Currently supported by QCG: logx, logy, logz, gridx, gridy, gridz
125+
* @param objectName Name of the object affected by these drawOptions.
126+
* @param options The list of hints.
127+
* @throw ObjectNotFoundError if object is not found.
128+
*/
129+
void setDisplayHint(const std::string& objectName, const std::string& hints);
130+
131+
/**
132+
* See setDisplayHint(const std::string& objectName, const std::string& hints).
133+
*/
134+
void setDisplayHint(TObject* obj, const std::string& hints);
135+
101136
/**
102137
* Get the number of objects that have been published.
103138
* @return an int with the number of objects.

Framework/src/CcdbDatabase.cxx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,21 @@
3131
#include <chrono>
3232
#include <sstream>
3333
#include <unordered_set>
34-
34+
// boost
3535
#include <boost/algorithm/string.hpp>
3636
#include <boost/property_tree/json_parser.hpp>
3737
#include <boost/property_tree/ptree.hpp>
3838
#include <boost/foreach.hpp>
39+
// misc
40+
#include "rapidjson/document.h"
41+
#include "rapidjson/stringbuffer.h"
42+
#include "rapidjson/writer.h"
3943

4044
using namespace std::chrono;
4145
using namespace AliceO2::Common;
4246
using namespace o2::quality_control::core;
4347
using namespace std;
48+
using namespace rapidjson;
4449

4550
namespace o2::quality_control::repository
4651
{
@@ -244,12 +249,15 @@ std::string CcdbDatabase::retrieveMOJson(std::string taskName, std::string objec
244249
std::string CcdbDatabase::retrieveJson(std::string path, long timestamp, const std::map<std::string, std::string>& metadata)
245250
{
246251
map<string, string> headers;
247-
auto tobj = retrieveTObject(path, metadata, timestamp, &headers);
252+
Document jsonDocument;
248253

254+
// Get object
255+
auto* tobj = retrieveTObject(path, metadata, timestamp, &headers);
249256
if (tobj == nullptr) {
250257
return std::string();
251258
}
252259

260+
// Convert object to JSON string
253261
TObject* toConvert = nullptr;
254262
if (tobj->IsA() == MonitorObject::Class()) { // a full MO -> pre-v0.25
255263
std::shared_ptr<MonitorObject> mo(dynamic_cast<MonitorObject*>(tobj));
@@ -267,7 +275,26 @@ std::string CcdbDatabase::retrieveJson(std::string path, long timestamp, const s
267275
TString json = TBufferJSON::ConvertToJSON(toConvert);
268276
delete toConvert;
269277

270-
return json.Data();
278+
// Prepare JSON document and add metadata
279+
if (jsonDocument.Parse(json.Data()).HasParseError()) {
280+
ILOG(Error) << "Unable to parse the JSON returned by TBufferJSON for object " << path << ENDM;
281+
return std::string();
282+
}
283+
rapidjson::Document::AllocatorType& allocator = jsonDocument.GetAllocator();
284+
rapidjson::Value object(rapidjson::Type::kObjectType);
285+
for (auto const& [key, value] : headers) {
286+
rapidjson::Value k(key.c_str(), allocator);
287+
rapidjson::Value v(value.c_str(), allocator);
288+
object.AddMember(k, v, allocator);
289+
}
290+
jsonDocument.AddMember("metadata", object, allocator);
291+
292+
// Convert to string
293+
StringBuffer buffer;
294+
buffer.Clear();
295+
Writer<rapidjson::StringBuffer> writer(buffer);
296+
jsonDocument.Accept(writer);
297+
return strdup(buffer.GetString());
271298
}
272299

273300
void CcdbDatabase::disconnect()

Framework/src/MonitorObject.cxx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ void MonitorObject::updateMetadata(std::string key, std::string value)
8686
}
8787
}
8888

89+
void MonitorObject::addOrUpdateMetadata(std::string key, std::string value)
90+
{
91+
if (mUserMetadata.count(key) > 0) {
92+
mUserMetadata[key] = value;
93+
} else {
94+
mUserMetadata.insert({ key, value });
95+
}
96+
}
97+
8998
std::string MonitorObject::getPath() const
9099
{
91100
string path = "qc/" + getDetectorName() + "/" + getTaskName() + "/" + getName();

Framework/src/ObjectsManager.cxx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ using namespace std;
2828
namespace o2::quality_control::core
2929
{
3030

31+
const std::string ObjectsManager::gDrawOptionsKey = "drawOptions";
32+
const std::string ObjectsManager::gDisplayHintsKey = "displayHints";
33+
3134
ObjectsManager::ObjectsManager(TaskConfig& taskConfig, bool noDiscovery) : mTaskConfig(taskConfig), mUpdateServiceDiscovery(false)
3235
{
3336
mMonitorObjects = std::make_unique<MonitorObjectCollection>();
@@ -125,4 +128,28 @@ int ObjectsManager::getNumberPublishedObjects()
125128
return mMonitorObjects->GetLast() + 1; // GetLast returns the index
126129
}
127130

131+
void ObjectsManager::setDefaultDrawOptions(const std::string& objectName, const std::string& options)
132+
{
133+
MonitorObject* mo = getMonitorObject(objectName);
134+
mo->addOrUpdateMetadata(gDrawOptionsKey, options);
135+
}
136+
137+
void ObjectsManager::setDefaultDrawOptions(TObject* obj, const std::string& options)
138+
{
139+
MonitorObject* mo = getMonitorObject(obj->GetName());
140+
mo->addOrUpdateMetadata(gDrawOptionsKey, options);
141+
}
142+
143+
void ObjectsManager::setDisplayHint(const std::string& objectName, const std::string& hints)
144+
{
145+
MonitorObject* mo = getMonitorObject(objectName);
146+
mo->addOrUpdateMetadata(gDisplayHintsKey, hints);
147+
}
148+
149+
void ObjectsManager::setDisplayHint(TObject* obj, const std::string& hints)
150+
{
151+
MonitorObject* mo = getMonitorObject(obj->GetName());
152+
mo->addOrUpdateMetadata(gDisplayHintsKey, hints);
153+
}
154+
128155
} // namespace o2::quality_control::core

Framework/test/testCcdbDatabase.cxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include <boost/test/unit_test.hpp>
2828
#include <TH1F.h>
29+
#include "rapidjson/document.h"
2930

3031
namespace utf = boost::unit_test;
3132

@@ -38,6 +39,7 @@ namespace
3839
using namespace o2::quality_control::core;
3940
using namespace o2::quality_control::repository;
4041
using namespace std;
42+
using namespace rapidjson;
4143

4244
const std::string CCDB_ENDPOINT = "ccdb-test.cern.ch:8080";
4345

@@ -207,6 +209,15 @@ BOOST_AUTO_TEST_CASE(ccdb_retrieve_json, *utf::depends_on("ccdb_store"))
207209
auto json4 = f.backend->retrieveQOJson(qualityPath);
208210
BOOST_CHECK(!json3.empty());
209211
BOOST_CHECK_EQUAL(json3, json4);
212+
213+
Document jsonDocument;
214+
jsonDocument.Parse(json.c_str());
215+
BOOST_CHECK(jsonDocument["_typename"].IsString());
216+
BOOST_CHECK_EQUAL(jsonDocument["_typename"].GetString(), "TH1F");
217+
BOOST_CHECK(jsonDocument.FindMember("metadata") != jsonDocument.MemberEnd());
218+
const Value& metadataNode = jsonDocument["metadata"];
219+
BOOST_CHECK(metadataNode.IsObject());
220+
BOOST_CHECK(metadataNode.FindMember("qc_task_name") != jsonDocument.MemberEnd());
210221
}
211222

212223
BOOST_AUTO_TEST_CASE(ccdb_retrieve_mo_json, *utf::depends_on("ccdb_store"))

Framework/test/testObjectsManager.cxx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,27 @@ BOOST_AUTO_TEST_CASE(metadata_test)
126126
BOOST_CHECK_EQUAL(objectsManager.getMonitorObject("content")->getMetadataMap().at("aaa"), "bbb");
127127
}
128128

129+
BOOST_AUTO_TEST_CASE(drawOptions_test)
130+
{
131+
TaskConfig config;
132+
config.taskName = "test";
133+
config.consulUrl = "http://consul-test.cern.ch:8500";
134+
ObjectsManager objectsManager(config, true);
135+
136+
TH1F h("histo", "h", 100, 0, 99);
137+
objectsManager.startPublishing(&h);
138+
139+
BOOST_CHECK_THROW(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDrawOptionsKey), out_of_range);
140+
objectsManager.setDefaultDrawOptions(&h, "colz");
141+
BOOST_CHECK_EQUAL(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDrawOptionsKey), "colz");
142+
objectsManager.setDefaultDrawOptions("histo", "alp lego1");
143+
BOOST_CHECK_EQUAL(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDrawOptionsKey), "alp lego1");
144+
145+
BOOST_CHECK_THROW(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDisplayHintsKey), out_of_range);
146+
objectsManager.setDisplayHint(&h, "logx");
147+
BOOST_CHECK_EQUAL(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDisplayHintsKey), "logx");
148+
objectsManager.setDisplayHint("histo", "gridy logy");
149+
BOOST_CHECK_EQUAL(objectsManager.getMonitorObject("histo")->getMetadataMap().at(ObjectsManager::gDisplayHintsKey), "gridy logy");
150+
}
151+
129152
} // namespace o2::quality_control::core

0 commit comments

Comments
 (0)