<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _log(pid, request, event, timestamp=None):
 """Log an operation that was performed on a sciobj."""

    # Support logging events that are not associated with an object.
    sciobj_model = None
    if pid is not None:
        try:
            sciobj_model = d1_gmn.app.models.ScienceObject.objects.filter(pid__did=pid)[
                0
            ]
        except IndexError:
            raise d1_common.types.exceptions.ServiceFailure(
                0,
                'Attempted to create event log for non-existing object. pid="{}"'.format(
                    pid
                ),
            )

    event_log_model = create_log_entry(
        sciobj_model,
        event,
        request.META['REMOTE_ADDR'],
        request.META.get('HTTP_USER_AGENT', '<not provided>'),
        request.primary_subject_str,
    )

    # The datetime is an optional parameter. If it is not provided, a
    # "auto_now_add=True" value in the the model defaults it to Now. The
    # disadvantage to this approach is that we have to update the timestamp in a
    # separate step if we want to set it to anything other than Now.
    if timestamp is not None:
        event_log_model.timestamp = timestamp
        event_log_model.save()