access, get insights into the bucket usage and use the logs as a journal for bucket changes.
The log records are stored in objects in a separate bucket and can be analyzed later.
Logging configuration is done at the bucket level and can be enabled or disabled at any time.
-The log bucket can accumulate logs from multiple buckets. It is recommended to configured
+The log bucket can accumulate logs from multiple buckets. It is recommended to configured
a different "prefix" for each bucket, so that the logs of different buckets will be stored
in different objects in the log bucket.
Journal
```````
-If logging type is set to "Journal", the records are written to the log bucket before the bucket operation is completed.
-This means that if the logging action fails, the operation will not be executed, and an error will be returned to the client.
-An exception to the above are "multi/delete" log records: if writing these log records fail, the operation continues and may still be successful.
+If logging type is set to "Journal", the records are written to the log bucket before the bucket operation is completed.
+This means that if the logging action fails, the operation will not be executed, and an error will be returned to the client
+Some exceptions exists to that rule, the "Fails Operation" columns in the table below indicate by "No" which operations will not fail even if logging failed.
Journal mode supports filtering out records based on matches of the prefixes and suffixes of the logged object keys. Regular-expression matching can also be used on these to create filters.
Note that it may happen that the log records were successfully written, but the bucket operation failed, since the logs are written.
+The following operation are supported in journal mode:
+
++-------------------------------+-------------------------------------+-----------------+
+| Operation | Operation Name | Fails Operation |
++===============================+=====================================+=================+
+| ``PutObject`` | ``REST.PUT.OBJECT`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``DeleteObject`` | ``REST.DELETE.OBJECT`` | No |
++-------------------------------+-------------------------------------+-----------------+
+| ``DeleteObjects`` | ``REST.POST.DELETE_MULTI_OBJECT`` | No |
++-------------------------------+-------------------------------------+-----------------+
+| ``CompleteMultipartUpload`` | ``REST.POST.UPLOAD`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``CopyObject`` | ``REST.PUT.OBJECT`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``PutObjectAcl`` | ``REST.PUT.ACL`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``PutObjectLegalHold`` | ``REST.PUT.LEGAL_HOLD`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``PutObjectRetention`` | ``REST.PUT.RETENTION`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``PutObjectTagging`` | ``REST.PUT.OBJECT_TAGGING`` | Yes |
++-------------------------------+-------------------------------------+-----------------+
+| ``DeleteObjectTagging`` | ``REST.DELETE.OBJECT_TAGGING`` | No |
++-------------------------------+-------------------------------------+-----------------+
+
Bucket Logging Policy
---------------------
| ``LoggingType`` | String | The type of logging. Valid values are: | No |
| | | ``Standard`` (default) all bucket operations are logged after being perfomed. | |
| | | The log record will contain all fields. | |
-| | | ``Journal`` only PUT, COPY, MULTI/DELETE and MPU operations are logged. | |
+| | | ``Journal`` only operations that modify and object are logged. | |
| | | Will record the minimum subset of fields in the log record that is needed | |
| | | for journaling. | |
+-------------------------------+-----------+--------------------------------------------------------------------------------------+----------+
return;
}
+ op_ret = s->object->get_obj_attrs(y, this);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "ERROR: failed to get obj attrs, obj=" << s->object
+ << " ret=" << op_ret << dendl;
+ return;
+ }
+ const auto etag = s->object->get_attrs()[RGW_ATTR_ETAG].to_str();
+ op_ret = rgw::bucketlogging::log_record(driver,
+ rgw::bucketlogging::LoggingType::Journal,
+ s->object.get(),
+ s,
+ canonical_name(),
+ etag,
+ s->object->get_size(),
+ this, y, false, false);
+ if (op_ret < 0) {
+ return;
+ }
+
s->object->set_atomic(true);
op_ret = s->object->modify_obj_attrs(RGW_ATTR_TAGS, tags_bl, y, this);
if (op_ret == -ECANCELED){
if (rgw::sal::Object::empty(s->object.get()))
return;
+ op_ret = s->object->get_obj_attrs(y, this);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "ERROR: failed to get obj attrs, obj=" << s->object
+ << " ret=" << op_ret << dendl;
+ return;
+ }
+ const auto etag = s->object->get_attrs()[RGW_ATTR_ETAG].to_str();
+ op_ret = rgw::bucketlogging::log_record(driver,
+ rgw::bucketlogging::LoggingType::Journal,
+ s->object.get(),
+ s,
+ canonical_name(),
+ etag,
+ s->object->get_size(),
+ this, y, false, false);
+ if (op_ret < 0) {
+ return;
+ }
+
op_ret = s->object->delete_obj_attrs(this, RGW_ATTR_TAGS, y);
}
return;
}
+ const auto etag = s->object->get_attrs()[RGW_ATTR_ETAG].to_str();
+ op_ret = rgw::bucketlogging::log_record(driver,
+ rgw::bucketlogging::LoggingType::Journal,
+ s->object.get(),
+ s,
+ canonical_name(),
+ etag,
+ s->object->get_size(),
+ this, y, false, false);
+ if (op_ret < 0) {
+ return;
+ }
+
bufferlist bl;
new_policy.encode(bl);
map<string, bufferlist> attrs;
}
}
+ const auto etag = s->object->get_attrs()[RGW_ATTR_ETAG].to_str();
+ op_ret = rgw::bucketlogging::log_record(driver,
+ rgw::bucketlogging::LoggingType::Journal,
+ s->object.get(),
+ s,
+ canonical_name(),
+ etag,
+ s->object->get_size(),
+ this, y, false, false);
+ if (op_ret < 0) {
+ return;
+ }
+
op_ret = s->object->modify_obj_attrs(RGW_ATTR_OBJECT_RETENTION, bl, s->yield, this);
return;
op_ret = -ERR_MALFORMED_XML;
return;
}
+
+ op_ret = s->object->get_obj_attrs(y, this);
+ if (op_ret < 0) {
+ ldpp_dout(this, 0) << "ERROR: failed to get obj attrs, obj=" << s->object
+ << " ret=" << op_ret << dendl;
+ return;
+ }
+ const auto etag = s->object->get_attrs()[RGW_ATTR_ETAG].to_str();
+ op_ret = rgw::bucketlogging::log_record(driver,
+ rgw::bucketlogging::LoggingType::Journal,
+ s->object.get(),
+ s,
+ canonical_name(),
+ etag,
+ s->object->get_size(),
+ this, y, false, false);
+ if (op_ret < 0) {
+ return;
+ }
+
bufferlist bl;
obj_legal_hold.encode(bl);
//if instance is empty, we should modify the latest object
public:
RGWPutObjRetention_ObjStore() = default;
~RGWPutObjRetention_ObjStore() override = default;
+ virtual std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
};
class RGWGetObjRetention_ObjStore : public RGWGetObjRetention {
public:
RGWGetObjRetention_ObjStore() = default;
~RGWGetObjRetention_ObjStore() = default;
+ virtual std::string canonical_name() const override { return fmt::format("REST.{}.RETENTION", s->info.method); }
};
class RGWPutObjLegalHold_ObjStore : public RGWPutObjLegalHold {
RGWPutObjLegalHold_ObjStore() = default;
~RGWPutObjLegalHold_ObjStore() override = default;
int get_params(optional_yield y) override;
+ virtual std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
};
class RGWGetObjLegalHold_ObjStore : public RGWGetObjLegalHold {
public:
RGWGetObjLegalHold_ObjStore() = default;
+ virtual std::string canonical_name() const override { return fmt::format("REST.{}.LEGAL_HOLD", s->info.method); }
~RGWGetObjLegalHold_ObjStore() = default;
};
public:
~RGWDeleteObjTags_ObjStore_S3() override {}
void send_response() override;
+ virtual std::string canonical_name() const override { return fmt::format("REST.{}.OBJECT_TAGGING", s->info.method); }
};
class RGWGetBucketTags_ObjStore_S3 : public RGWGetBucketTags_ObjStore