

chromeのconsole上において(iframeで読み込まれ勝手に)consoleに出力されたものを
文字列として変数に入れてhtmlに出力したいのですが どのような方法がありますでしょうか？

よろしくお願いいたします。


CC BY-SA 3.0
2014-12-22T14:42:39.997
2388
2014-12-23T04:42:42.583
2014-12-23T01:25:01.603
30
5528
question
javascript google-chrome-devtools
console.logの履歴にアクセスしたいのですがどうすればよいでしょうか？


直接console.logの履歴にアクセスする方法ではありませんが、[Sinon.js](http://sinonjs.org)のようなテストフレームワークを使うと同様の事が出来そうです。  
例えば、メソッドが呼ばれた時の引数や戻り値、エラーなどを監視するSpyを使うと、以下のような感じでconsole.logの引数に渡された文字列を取得できます（firstlogに"hoge"、secondlogに"moge"が入ります）。

[code]

    var spy = sinon.spy(console, "log");
    console.log("hoge");
    console.log("moge");
    var firstlog = spy.getCall(0).args[0];
    var secondlog = spy.getCall(1).args[0];
    
[/code]


CC BY-SA 3.0
2014-12-22T15:40:57.427
2390
2014-12-22T15:40:57.427
33
2388
answer


ライブラリを使わない方法(のヒント)を提示しておきます。

# オリジンが同じ場合

iframe の DOM ノードには `contentWindow` というオブジェクトが存在します。 これは iframe 内の `window`
と同じものです。 **幾つかの条件を満たす時には** 、外側のフレームから この `contentWindow` の内部を書き換えることができます

このことを利用して `contentWindow.console.log` やその他を別の関数に差し替えてしまえば、 iframe 内から
`console.log` への出力(全履歴)を、外側から知ることができます。 おおよそのコードはこんな感じですね。

[code]

    // 文章内の最初の iframe を取得する。必要に応じて取り方は変えるべし
    var firstFrame = document.getElementsByTagName('iframe')[0];
    
    firstFrame.contentWindow.console.log = function() {
      // TODO: arguments を履歴として記録する
    }
    
[/code]

なお **幾つかの条件** とはおおよそ以下のとおりで、全て満たしている場合にのみ書き換え可能なはずです。(動作確認はしていない)

  * iframe ノードが document の下にぶら下がっている
  * 外側と iframe 内のコンテンツの生成元(オリジン)が同一である
  * sandbox 制限がかかっていない

参考文献: [インラインフレームについて - JavaScriptプログラミング講座](http://hakuhin.jp/js/iframe.html)

# オリジンが異なる場合

仮に iframe 内側のコンテンツに任意のJavaScriptを入れられるようならば、 オリジンが異なる場合にも対応する方法があります。 それは
[`parent.postMessage`](https://developer.mozilla.org/ja/docs/DOM/window.postMessage)
を使う方法です。

説明は、簡単なコードを示すに留めますが以下のようになります。 なおコードには onload からの呼び出しなどは含まれていませんので、
必要に応じて適宜補ってください。

### iframe の内側の JavaScript

[code]

    console.log = function () {
      parent.postMessage(JSON.stringify(arguments), '*')
    }
    
[/code]

### 外側の JavaScript

[code]

    window.addEventListener("message", receiveMessage, false);
    
    function receiveMessage(ev) {
      // 期待した生成元(オリジン)からのメッセージであるかを確認する
      if (ev.origin === 'http://example.org/') {
        // 履歴に記録する
      }
    }
    
[/code]


CC BY-SA 3.0
2014-12-23T02:15:07.237
2407
2014-12-23T02:15:07.237
208
2388
answer


Google Chromeの拡張からであれば、 [chrome.experimental.devtools.console
API](https://developer.chrome.com/extensions/experimental_devtools_console)を利用してコンソールの履歴にアクセスできます。

このAPIは開発者ツール内からしか利用できないので、開発者ツールを拡張する「拡張」として書く必要があります。そしてログを取得するには開発者ツールを開く必要がある、という制約が付きます。また実験段階のAPIなので、ブラウザの設定をいじって利用を許可する必要もあります。流れとしては:

  1. chrome://flags/#extension-apis を開き、"Experimental Extension APIs"を有効にしておく
  2. experimental パーミッションを manifest.json に含め、 devtools_page でHTMLファイルを指定する
[code]     ...

    "permissions": [
      "experimental"
    ],
    "devtools_page": "devtools.html",
    ...
    
[/code]

  3. devtools.html から参照されるスクリプトで履歴用 API を使う

のようになります。

## 元のドキュメントに出力する

[メッセージングAPI](https://developer.chrome.com/extensions/messaging)を利用して、開発者ツール内から元のドキュメントに出力できます:

devtools.html から参照されるスクリプトからメッセージを送信し:

[code]

    // <script src="devtools.js"></script> などで指定したファイル内
    chrome.experimental.devtools.console.onMessageAdded.addListener(function(message) {
      chrome.runtime.sendMessage({
        "to": chrome.devtools.inspectedWindow.tabId,
        "payload": message
      });
    });
    
[/code]

[Event
Page](https://developer.chrome.com/extensions/event_pages)のスクリプトで受け取り、[Content
Script](https://developer.chrome.com/extensions/content_scripts)に中継する:

[code]

    // マニフェストの "background": {"scripts": [...]} で指定したファイル内
    chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
      chrome.tabs.sendMessage(message.to, message.payload, sendResponse);
    });
    
[/code]

Content Script側で元のドキュメントに出力する:

[code]

    // マニフェストの "content_scripts": [...] で指定したファイル内
    chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
      var log = document.createElement('div');
      log.innerHTML = JSON.stringify(message);
      document.body.appendChild(log);
    });
    
[/code]

[開発者ツール用拡張のドキュメント](https://developer.chrome.com/extensions/devtools#solutions)でもメッセージングAPIを使ういくつかのユースケースが解説されています。


CC BY-SA 3.0
2014-12-23T04:42:42.583
2413
2014-12-23T04:42:42.583
30
2388
answer