diff --git a/packages/@ember/-internals/glimmer/lib/helpers/-log-action.ts b/packages/@ember/-internals/glimmer/lib/helpers/-log-action.ts
new file mode 100644
index 00000000000..887bdf49124
--- /dev/null
+++ b/packages/@ember/-internals/glimmer/lib/helpers/-log-action.ts
@@ -0,0 +1,19 @@
+import { Arguments, VM } from '@glimmer/runtime';
+import { ACTION, UnboundReference } from '../utils/references';
+
+export default function logAction(_vm: VM, args: Arguments) {
+ let { positional } = args;
+ let capturedArgs = positional.capture();
+
+ const fn = function() {
+ let allArgs = capturedArgs.value().concat(...arguments);
+
+ /* eslint-disable no-console */
+ console.log(...allArgs);
+ /* eslint-enable no-console */
+ };
+
+ fn[ACTION] = true;
+
+ return new UnboundReference(fn);
+}
diff --git a/packages/@ember/-internals/glimmer/lib/resolver.ts b/packages/@ember/-internals/glimmer/lib/resolver.ts
index 53ec8cad3c3..3d8eca16b2b 100644
--- a/packages/@ember/-internals/glimmer/lib/resolver.ts
+++ b/packages/@ember/-internals/glimmer/lib/resolver.ts
@@ -27,6 +27,7 @@ import { isHelperFactory, isSimpleHelper } from './helper';
import { default as componentAssertionHelper } from './helpers/-assert-implicit-component-helper-argument';
import { default as classHelper } from './helpers/-class';
import { default as inputTypeHelper } from './helpers/-input-type';
+import { default as logAction } from './helpers/-log-action';
import { default as normalizeClassHelper } from './helpers/-normalize-class';
import { default as action } from './helpers/action';
import { default as array } from './helpers/array';
@@ -74,6 +75,7 @@ const BUILTINS_HELPERS = {
readonly,
unbound,
unless: inlineUnless,
+ '-log-action': logAction,
'-class': classHelper,
'-each-in': eachIn,
'-input-type': inputTypeHelper,
diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/log-action-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/log-action-test.js
new file mode 100644
index 00000000000..8eccdf81db4
--- /dev/null
+++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/log-action-test.js
@@ -0,0 +1,69 @@
+/*globals MouseEvent */
+import { RenderingTestCase, moduleFor } from 'internal-test-helpers';
+
+moduleFor(
+ 'Helpers test: {{-log-action}}',
+ class extends RenderingTestCase {
+ constructor() {
+ super(...arguments);
+ /* eslint-disable no-console */
+ this.originalLog = console.log;
+ this.logCalls = [];
+ console.log = (...args) => {
+ this.logCalls.push(...args);
+ /* eslint-enable no-console */
+ };
+ }
+
+ teardown() {
+ super.teardown();
+ /* eslint-disable no-console */
+ console.log = this.originalLog;
+ /* eslint-enable no-console */
+ }
+
+ ['@test can log as action']() {
+ this.render(``);
+ this.$('#my-btn').click();
+
+ this.assert.strictEqual(this.logCalls.length, 1);
+ this.assert.ok(this.logCalls[0] instanceof MouseEvent);
+ }
+
+ ['@test can log with multiple args']() {
+ this.render(``);
+ this.$('#my-btn').click();
+
+ this.assert.strictEqual(this.logCalls.length, 3);
+ this.assert.equal(this.logCalls[0], 'rainbow');
+ this.assert.equal(this.logCalls[1], 45);
+ this.assert.ok(this.logCalls[2] instanceof MouseEvent);
+ }
+
+ ['@test can log with reference value']() {
+ this.render(``, {
+ age: 21,
+ });
+ this.$('#my-btn').click();
+
+ this.assert.strictEqual(this.logCalls.length, 3);
+ this.assert.equal(this.logCalls[0], 21);
+ this.assert.equal(this.logCalls[1], 'rainbow');
+ this.assert.ok(this.logCalls[2] instanceof MouseEvent);
+ }
+
+ ['@test can use with `action` helper combination']() {
+ this.render(
+ ``,
+ { age: 21 }
+ );
+ this.$('#my-btn').click();
+
+ this.assert.strictEqual(this.logCalls.length, 4);
+ this.assert.equal(this.logCalls[0], 21);
+ this.assert.equal(this.logCalls[1], 'rainbow');
+ this.assert.equal(this.logCalls[2], 'sun');
+ this.assert.ok(this.logCalls[3] instanceof MouseEvent);
+ }
+ }
+);
diff --git a/packages/ember-template-compiler/lib/plugins/index.ts b/packages/ember-template-compiler/lib/plugins/index.ts
index 6a168cf6f95..b48c9c32a60 100644
--- a/packages/ember-template-compiler/lib/plugins/index.ts
+++ b/packages/ember-template-compiler/lib/plugins/index.ts
@@ -13,6 +13,7 @@ import TransformHasBlockSyntax from './transform-has-block-syntax';
import TransformInElement from './transform-in-element';
import TransformInputTypeSyntax from './transform-input-type-syntax';
import TransformLinkTo from './transform-link-to';
+import TransformLogAction from './transform-log-action';
import TransformOldClassBindingSyntax from './transform-old-class-binding-syntax';
import TransformQuotedBindingsIntoJustBindings from './transform-quoted-bindings-into-just-bindings';
@@ -40,6 +41,7 @@ const transforms: Array = [
TransformInElement,
AssertIfHelperWithoutArguments,
AssertSplattributeExpressions,
+ TransformLogAction,
];
if (!EMBER_GLIMMER_ANGLE_BRACKET_BUILT_INS) {
diff --git a/packages/ember-template-compiler/lib/plugins/transform-log-action.ts b/packages/ember-template-compiler/lib/plugins/transform-log-action.ts
new file mode 100644
index 00000000000..adc22875472
--- /dev/null
+++ b/packages/ember-template-compiler/lib/plugins/transform-log-action.ts
@@ -0,0 +1,65 @@
+import { AST, ASTPlugin, ASTPluginEnvironment } from '@glimmer/syntax';
+
+/**
+ @module ember
+*/
+
+/**
+ A Glimmer2 AST transformation that replaces all instances of
+
+ ```handlebars
+