Problem/Motivation

Processors skip_on_empty and skip_row_if_not_set are not logging any message when they are skipping rows. But such information is very useful for content managers.

Proposed resolution

Allow skip_on_empty and skip_row_if_not_set processors to specify a customized message to be logged when a row is skipped.

Remaining tasks

None.

User interface changes

None.

API changes

None.

Data model changes

New message configuration in skip_on_empty and skip_row_if_not_set plugins.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

generalredneck created an issue. See original summary.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mikeryan’s picture

Title: Log Exceptions thrown in watchdog for ignored source rows. » Log Exceptions thrown in message table for ignored source rows.

The migration message table is the logical place for row-specific messages like this. Should be fairly simple - where MigrateSkipRowException is caught, do a $this->idMap->saveMessage(). And of course anything that throws MigrateSkipRowException should be giving it a message...

generalredneck’s picture

Status: Active » Needs review
FileSize
530 bytes

looks like it may be as simple as this... though we may want to have a different message level for skipped messages... but the default for all Migration Exceptions is MigrationInterface::MESSAGE_ERROR.

Status: Needs review » Needs work

The last submitted patch, 4: migrate-log_skip_messages-2655154-4-D8.1.x.patch, failed testing.

generalredneck’s picture

Ok my bad... for some reason I thought MigrateSkipRowException extended the MigrateEsception... Fixed the level to use MigrateIdMapInterface::STATUS_IGNORED

generalredneck’s picture

Status: Needs work » Needs review
mikeryan’s picture

Status: Needs review » Needs work
+++ b/core/modules/migrate/src/MigrateExecutable.php
@@ -224,6 +224,7 @@ public function import() {
+        $this->saveMessage($e->getMessage(), MigrateIdMapInterface::STATUS_IGNORED);

Let's skip this when the message is empty, no point in cluttering the message table with empty messages.

A test would be good.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

generalredneck’s picture

@mikeryan
I need a little help. I've figured out how to test the migration and added a little bit to the MigrateSkipRowTest. The challenge I'm facing is how to grab the message that is being pushed to MigrationExecutable::saveMessage(). This ultimatly calls the MigrateIdMapInterface class... which the instance class in this case is Drupal\migrate\Plugin\migrate\id_map\Sql. This is a problem since I don't think I can do an $this->installSchema() with dynamically created tables... maybe you can help me there... BUT I think the right way to handle this is to use the Event Dispatcher called by line 639 on that class.

 $this->eventDispatcher->dispatch(MigrateEvents::IDMAP_MESSAGE,
      new MigrateIdMapMessageEvent($this->migration, $source_id_values, $message, $level));

My problem is I don't know how to hook into the eventDispatcher... if you can point me in the right direction... I'll update one of the test modules to pick it up and we can verify the test this way by saving the messages since they aren't ever stored (except in the database) using Drupal\migrate\Plugin\migrate\id_map\Sql::saveMessage()

generalredneck’s picture

And then I got to thinking...

The Drupal\migrate\Plugin\migrate\id_map\Sql class probably would have errored out if the table didn't exist... as there is no checking for it. I see that the table is created on the fly. I'll just check that. :P

generalredneck’s picture

Added tests (both unit and Kernel) to test the changes I made. I added messages to SkipOnEmpty unless you add a quiet configuration. That's tested here as well. I also added logging messages for "prepareRow" as that wasn't the case before (as the tests pointed out to me).

mikeryan’s picture

Assigned: Unassigned » mikeryan
mikeryan’s picture

Title: Log Exceptions thrown in message table for ignored source rows. » Optionally log messages for skip_on_empty
Status: Needs review » Needs work
Issue tags: +Needs reroll
Related issues: +#2818871: Allow logging skip row exception messages

@generalredneck: I'm very sorry I didn't get back to this issue more promptly, or immediately recall it when getting involved with reviewing #2818871: Allow logging skip row exception messages - that issue covers much of your work here (with identical code - you deserve an issue credit on that). For what it's worth, on today's migrate maintainer call we discussed doing a better job of keeping up with the "Needs review" issues for the migration system so patches don't languish - we formally parceled out the oldest (least-recently-updated) in the queue, which is how I came back to this one. We should do better going forward.

Having an option to log the skip_on_empty process plugin is still a good idea, though - you'll need to reroll due to the redundant changes in the other issue.

+++ b/core/modules/migrate/src/Plugin/migrate/process/SkipOnEmpty.php
@@ -24,7 +24,13 @@ class SkipOnEmpty extends ProcessPluginBase {
+      if (isset($this->configuration['quiet']) && $this->configuration['quiet']) {

I think a "log_message" configuration option (with the opposite sense) would be more clear, with the default in its absence being not to log (maintaining the current behavior and not surprising people with messages they weren't expecting).

generalredneck’s picture

I had the same thought after I made the patch but I though I woudl see what you said. I'll get us an update.

generalredneck’s picture

Status: Needs review » Needs work

The last submitted patch, 16: migrate-allow_log_skip_row-2655154-16-D8.2.patch, failed testing.

mikeryan’s picture

Status: Needs work » Needs review

Weird, I don't see why this patch would introduce requirements failures - retesting.

Status: Needs review » Needs work

The last submitted patch, 16: migrate-allow_log_skip_row-2655154-16-D8.2.patch, failed testing.

mikeryan’s picture

+++ b/core/modules/migrate/src/Plugin/migrate/process/SkipOnEmpty.php
@@ -24,7 +26,13 @@ class SkipOnEmpty extends ProcessPluginBase {
+      throw new MigrateSkipRowException($message, !empty($message));

Here's the problem - remove the second argument, we should *always* record the skip in the map table.

olegel’s picture

I removed second argument ( !empty($message) )

lomasr’s picture

lomasr’s picture

Status: Needs work » Needs review
mikeryan’s picture

Status: Needs review » Needs work

Main patch looks good, just a couple of test tweaks...

  1. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -51,4 +51,37 @@ public function testRowBypassesOnNonEmpty() {
    +      (new SkipOnEmpty($configuration, 'skip_on_empty', []))
    +      ->transform('', $this->migrateExecutable, $this->row, 'destinationproperty');
    ...
    +      (new SkipOnEmpty($configuration, 'skip_on_empty', []))
    +      ->transform('', $this->migrateExecutable, $this->row, 'destinationproperty');
    

    The second line should be indented. Although, actually, I think it would be cleaner to assign to SkipOnEmpty plugin to a variable and call transform on the variable.

  2. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -51,4 +51,37 @@ public function testRowBypassesOnNonEmpty() {
    +    catch(\Drupal\migrate\MigrateSkipRowException $e) {
    ...
    +    catch(\Drupal\migrate\MigrateSkipRowException $e) {
    

    Please use a 'use' statement for the exception and reference it as simply MigrateSkipRowException.

mikeryan’s picture

Assigned: mikeryan » Unassigned

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

claudiu.cristea’s picture

+1 for this feature, but:

  1. We want flexible messages, instead of only logging a static message. For example a comment migration wants to say: Missed parent node and other migration something different, depending on its business logic. These messages are very valuable for content managers and operators.
  2. Not only skip_on_empty but also skip_row_if_not_set should benefit from this.

Redefining the IS according to these considerations.

phenaproxima’s picture

Status: Needs review » Needs work

Oh, but this is a great idea. The patch looks good. My concerns are nitpicks, code standards, and documentation-related.

  1. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipOnEmpty.php
    @@ -21,6 +21,9 @@
    + *   for this row. Logging a message has effect only for 'row' method. If is
    + *   missed, nothing is logged in the message table.
    

    The last sentence seems a bit unclear. And can the second-to-last sentence read "Messages are only logged for the 'row' skip level"?

  2. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipOnEmpty.php
    @@ -30,9 +33,11 @@
    + * If field_name is empty, skips the entire row and log 'Field field_name is
    

    s/log/logs

  3. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipRowIfNotSet.php
    @@ -16,6 +16,8 @@
    + *   for this row. If is missed, nothing is logged in the message table.
    

    The last sentence is phrased strangely. Maybe "is missed" should be "if not set"?

  4. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipRowIfNotSet.php
    @@ -26,10 +28,11 @@
    + * skipped and the "Missed the 'data' key" will be registered.
    

    This should end with "and the message "Missed the 'data' key" will be logged".

  5. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -51,4 +52,35 @@ public function testRowBypassesOnNonEmpty() {
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage
    +   */
    +  public function testRowSkipWithoutMessage() {
    

    I have recently been informed that we need to use $this->setExpectedException() in the test method, rather than the annotation.

  6. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -51,4 +52,35 @@ public function testRowBypassesOnNonEmpty() {
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage The value is empty
    +   */
    +  public function testRowSkipWithMessage() {
    

    Same here.

  7. +++ b/core/modules/migrate/tests/src/Unit/process/SkipRowIfNotSetTest.php
    @@ -0,0 +1,46 @@
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage
    +   */
    +  public function testRowSkipWithoutMessage() {
    

    And here.

  8. +++ b/core/modules/migrate/tests/src/Unit/process/SkipRowIfNotSetTest.php
    @@ -0,0 +1,46 @@
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage The 'some_key' key is not set
    +   */
    +  public function testRowSkipWithMessage() {
    

    And here.

gaurav.kapoor’s picture

Assigned: Unassigned » gaurav.kapoor
gaurav.kapoor’s picture

Assigned: gaurav.kapoor » Unassigned
Status: Needs work » Needs review
FileSize
7.16 KB
4.14 KB

Status: Needs review » Needs work

The last submitted patch, 30: 2655154-30.patch, failed testing.

claudiu.cristea’s picture

@phenaproxima

I have recently been informed that we need to use $this->setExpectedException() in the test method, rather than the annotation.

Why and where can I found docs about that?

gaurav.kapoor’s picture

There is an issue regarding this https://www.drupal.org/node/2822837 , but it has been postponed. So should we use method $this->setExpectedException() ?

claudiu.cristea’s picture

Indeed, a Coder policy is prepared in #2859286: Forbid @expectedException @expectedExceptionMessage.

  1. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -51,4 +52,35 @@ public function testRowBypassesOnNonEmpty() {
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage
    ...
    +   * @expectedException \Drupal\migrate\MigrateSkipRowException
    +   * @expectedExceptionMessage The value is empty
    
    +++ b/core/modules/migrate/tests/src/Unit/process/SkipRowIfNotSetTest.php
    @@ -0,0 +1,46 @@
    +   * @expectedExceptionMessage
    ...
    +    $this->setExpectedException(\Drupal\migrate\MigrateSkipRowException);
    ...
    +   * @expectedExceptionMessage The 'some_key' key is not set
    ...
    +    $this->setExpectedException(\Drupal\migrate\MigrateSkipRowException);
    

    All these annotations should be removed and $this->setException() should be before the point where the exception is expected. Also you'll need to pass the expected message. Use the MigrateSkipRowException::class form.

  2. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipOnEmpty.php
    @@ -30,9 +33,11 @@
    + * If field_name is empty, skips the entire row and logs 'Field field_name is
    + * missed' in the message table.
    

    ... and logs the message 'Field...

  3. +++ b/core/modules/migrate/src/Plugin/migrate/process/SkipRowIfNotSet.php
    @@ -16,6 +16,8 @@
    + *   for this row. If is missed, nothing is logged in the message table.
    

    Replace "If is missed... " with "If not set, nothing is logged in the message table."

  4. +++ b/core/modules/migrate/tests/src/Unit/process/SkipOnEmptyTest.php
    @@ -13,12 +14,12 @@ class SkipOnEmptyTest extends MigrateProcessTestCase {
    +    $this->setExpectedException(\Drupal\migrate\MigrateSkipProcessException);
    
    @@ -33,12 +34,12 @@ public function testProcessBypassesOnNonEmpty() {
    -   * @expectedException \Drupal\migrate\MigrateSkipRowException
    ...
    +    $this->setExpectedException(\Drupal\migrate\MigrateSkipRowException);
    

    Unrelated changes. Revert them.

claudiu.cristea’s picture

Status: Needs work » Needs review
FileSize
6.2 KB
6.23 KB

Fixed #34.

phenaproxima’s picture

Status: Needs review » Reviewed & tested by the community

Methinks it's ready. Thanks!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 35: 2655154-35.patch, failed testing.

claudiu.cristea’s picture

Issue tags: +Needs reroll
jofitz’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
6.22 KB

Re-rolled.

claudiu.cristea’s picture

Status: Needs review » Reviewed & tested by the community

It's only a reroll, so back to RTBC.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 39: 2655154-39.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Reviewed & tested by the community

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 39: 2655154-39.patch, failed testing.

claudiu.cristea’s picture

Status: Needs work » Reviewed & tested by the community
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

As this is a non breaking API addition to and experimental module backported to 8.3.x.

Committed and pushed e53654a to 8.4.x and bf80ef2 to 8.3.x. Thanks!

I discussed with @mikeryan today and he convinced me that this will be a useful change. We also discussed the possible of following up with a verbose switch to report all skipped rows.

  • alexpott committed e53654a on 8.4.x
    Issue #2655154 by generalredneck, claudiu.cristea, gaurav.kapoor, olegel...

  • alexpott committed bf80ef2 on 8.3.x
    Issue #2655154 by generalredneck, claudiu.cristea, gaurav.kapoor, olegel...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

rajeevku’s picture

$message = !empty($this->configuration['message']) ? $this->configuration['message'] : '';
+      throw new MigrateSkipRowException($message);

This one never works , throws exception but doesn't log anything.

heddn’s picture

drush mmsg %migration_id% should give you log results. If it doesn't, please open a new issue to investigate the regression.

dww’s picture

Dear people who added this cool feature:

a) Thanks!
b) RFC: #2960204: Make it possible for optional log messages from *skip* process plugins to contain context

Cheers,
-Derek