Add --variable_assignment_trace_filter option

In addition, write assignment event to the trace file.
diff --git a/src/eval.cc b/src/eval.cc
index 7f9dc6f..637f373 100644
--- a/src/eval.cc
+++ b/src/eval.cc
@@ -177,7 +177,7 @@
 
   trace_ = g_flags.dump_variable_assignment_trace || g_flags.dump_include_graph;
   assignment_tracefile_ = nullptr;
-  assignment_count_ = 0;
+  assignment_sep_ = "\n";
 }
 
 Evaluator::~Evaluator() {
@@ -345,6 +345,7 @@
   if (stmt->is_final) {
     var->SetReadOnly();
   }
+  TraceVariableAssign(lhs, var);
 }
 
 // With rule broken into
@@ -709,35 +710,70 @@
   return v;
 }
 
-void Evaluator::TraceVariableLookup(const char* operation,
-                                    Symbol name,
-                                    Var* var) {
+bool Evaluator::IsTraced(Symbol& name) const {
   if (assignment_tracefile_ == nullptr) {
+    return false;
+  }
+
+  bool trace_var = g_flags.traced_variables_pattern.size() == 0;
+  // trace every variable unless filtered
+  if (trace_var) {
+    return true;
+  }
+
+  for (const auto& pat : g_flags.traced_variables_pattern) {
+    if (pat.Match(name.c_str())) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void Evaluator::TraceVariableLookup(const char* operation,
+                                    Symbol& name,
+                                    Var* var) {
+  if (!IsTraced(name)) {
     return;
   }
 
-  if (assignment_count_++ == 0) {
-    fprintf(assignment_tracefile_, "\n");
-  } else {
-    fprintf(assignment_tracefile_, ",\n");
-  }
-
-  bool has_definition_trace = var->Definition() != nullptr;
-  fprintf(assignment_tracefile_, "    {\n");
-  fprintf(assignment_tracefile_, "      \"name\": \"%s\",\n", name.c_str());
-  fprintf(assignment_tracefile_, "      \"operation\": \"%s\",\n", operation);
-  fprintf(assignment_tracefile_, "      \"defined\": %s,\n",
-          var->IsDefined() ? "true" : "false");
+  fputs(assignment_sep_, assignment_tracefile_);
+  assignment_sep_ = ",\n";
+  fprintf(assignment_tracefile_,
+          "    {\n"
+          "      \"name\": \"%s\",\n"
+          "      \"operation\": \"%s\",\n"
+          "      \"defined\": %s,\n",
+          name.c_str(), operation, var->IsDefined() ? "true" : "false");
   fprintf(assignment_tracefile_, "      \"reference_stack\": [\n");
   CurrentFrame()->PrintJSONTrace(assignment_tracefile_, 8);
-  fprintf(assignment_tracefile_, "      ]%s\n",
-          has_definition_trace ? "," : "");
-  if (has_definition_trace) {
-    fprintf(assignment_tracefile_, "      \"value_stack\": [\n");
-    var->Definition()->PrintJSONTrace(assignment_tracefile_, 8);
-    fprintf(assignment_tracefile_, "      ]\n");
+  fprintf(assignment_tracefile_,
+          "      ]\n"
+          "    }");
+}
+
+void Evaluator::TraceVariableAssign(Symbol& name, Var* var) {
+  if (!IsTraced(name)) {
+    return;
   }
-  fprintf(assignment_tracefile_, "    }");
+  fputs(assignment_sep_, assignment_tracefile_);
+  assignment_sep_ = ",\n";
+  fprintf(assignment_tracefile_,
+          "    {\n"
+          "      \"name\": \"%s\",\n"
+          "      \"operation\": \"assign\",\n"
+          "      \"value\": \"%s\"",
+          name.c_str(), var->DebugString().c_str());
+  Frame* definition = var->Definition();
+  if (definition != nullptr) {
+    fprintf(assignment_tracefile_,
+            ",\n"
+            "      \"value_stack\": [\n");
+    definition->PrintJSONTrace(assignment_tracefile_, 8);
+    fprintf(assignment_tracefile_, "      ]");
+  }
+  fprintf(assignment_tracefile_,
+          "\n"
+          "    }");
 }
 
 Var* Evaluator::LookupVarForEval(Symbol name) {
diff --git a/src/eval.h b/src/eval.h
index 75038ef..fc7fcff 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -228,7 +228,9 @@
                bool* needs_assign);
   void DoInclude(const string& fname);
 
-  void TraceVariableLookup(const char* operation, Symbol name, Var* var);
+  bool IsTraced(Symbol& name) const;
+  void TraceVariableLookup(const char* operation, Symbol& name, Var* var);
+  void TraceVariableAssign(Symbol& name, Var* var);
   Var* LookupVarGlobal(Symbol name);
 
   // Equivalent to LookupVarInCurrentScope, but doesn't mark as used.
@@ -256,7 +258,7 @@
   bool trace_;
   std::vector<Frame*> stack_;
   FILE* assignment_tracefile_;
-  long int assignment_count_;
+  const char* assignment_sep_;
 
   std::vector<Loc> include_stack_;
 
diff --git a/src/flags.cc b/src/flags.cc
index e21a541..1bba336 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -53,6 +53,7 @@
   num_jobs = num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
   const char* num_jobs_str;
   const char* writable_str;
+  const char* variable_assignment_trace_filter;
 
   if (const char* makeflags = getenv("MAKEFLAGS")) {
     for (StringPiece tok : WordScanner(makeflags)) {
@@ -154,6 +155,12 @@
     } else if (ParseCommandLineOptionWithArg("--dump_variable_assignment_trace",
                                              argv, &i,
                                              &dump_variable_assignment_trace)) {
+    } else if (ParseCommandLineOptionWithArg(
+                   "--variable_assignment_trace_filter", argv, &i,
+                   &variable_assignment_trace_filter)) {
+      for (StringPiece pat : WordScanner(variable_assignment_trace_filter)) {
+        traced_variables_pattern.push_back(Pattern(pat));
+      }
     } else if (ParseCommandLineOptionWithArg("-j", argv, &i, &num_jobs_str)) {
       num_jobs = strtol(num_jobs_str, NULL, 10);
       if (num_jobs <= 0) {
@@ -202,4 +209,11 @@
       }
     }
   }
+
+  if (traced_variables_pattern.size() &&
+      dump_variable_assignment_trace == nullptr) {
+    ERROR(
+        "--variable_assignment_trace_filter is valid only together with "
+        "--dump_variable_assignment_trace");
+  }
 }
diff --git a/src/flags.h b/src/flags.h
index 73410d5..e173730 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -19,6 +19,7 @@
 #include <vector>
 
 #include "string_piece.h"
+#include "strutil.h"
 #include "symtab.h"
 
 using namespace std;
@@ -80,6 +81,7 @@
   vector<Symbol> targets;
   vector<StringPiece> cl_vars;
   vector<string> writable;
+  vector<Pattern> traced_variables_pattern;
 
   void Parse(int argc, char** argv);
 };
diff --git a/src/strutil.cc b/src/strutil.cc
index 8c4bdc0..4546265 100644
--- a/src/strutil.cc
+++ b/src/strutil.cc
@@ -160,8 +160,7 @@
 StringPiece Pattern::Stem(StringPiece str) const {
   if (!Match(str))
     return "";
-  return str.substr(percent_index_,
-                    str.size() - pat_.size() + 1);
+  return str.substr(percent_index_, str.size() - pat_.size() + 1);
 }
 
 void Pattern::AppendSubst(StringPiece str,